Módulo 2: Latencia y costo como arquitectura

7. El camino de la petición consciente del costo

Descripción

Al terminar esta lección vas a saber componer las cuatro piezas del módulo —presupuesto, cascade, caché, streaming— en un solo diseño coherente: el camino de la petición consciente del costo. Hasta ahora viste cada técnica por separado y contra su propio problema. Aquí las juntas en el orden en que una petición real las atraviesa: primero la caché (¿ya tengo esta respuesta?), luego el cascade (si no, ¿al barato o al caro?), con el presupuesto como la compuerta que verifica que el resultado cabe. Vas a aplicar esto al agente de soporte de Mercado —una feature conversacional donde el costo se acumula por turno— y vas a medir, ejecutando, la lección más importante de la síntesis: las técnicas se acumulan pero no suman, porque se solapan sobre el mismo tráfico barato, y ninguna sola basta —pero juntas meten la feature dentro de su presupuesto—.

Esto importa porque es el error opuesto al de mandar todo al modelo caro: creer que una sola técnica es la bala de plata. "Metimos caché, ya está" o "con el cascade sobra" son conclusiones tentadoras y falsas. Cada técnica ataca una parte del problema, y el presupuesto solo se respeta cuando las combinas —en el orden correcto, midiendo la combinación real, no sumando los ahorros por separado—. Componer bien es lo que separa una feature de IA que casi cabe en su presupuesto (y lo revienta cuando el tráfico crece) de una que cabe con holgura (headroom para crecer). Esta lección es donde el módulo deja de ser una caja de herramientas sueltas y se vuelve un método: dado un presupuesto, así se arma el camino que lo respeta.

Conexión con el módulo: esta es la síntesis. La lección 3 fijó el presupuesto como la restricción que ordena todo; las lecciones 4, 5 y 6 dieron las técnicas; esta las ensambla. Es la penúltima porque necesitabas cada pieza antes de poder componerlas, y prepara el proyecto (lección 8), donde harás lo mismo con tus manos sobre una feature distinta. Aquí también se cierra un hilo abierto: la lección 4 mostró que el cascade solo dejaba la búsqueda en $16,241/mes (sobre presupuesto), y la lección 5 mostró que la caché sola tampoco alcanzaba —esta lección demuestra, con números, por qué se necesitan juntas y cuánto rinde cada una encima de la otra—.

El camino de la petición: una fila con varias compuertas

Piénsalo así. Una petición que entra a tu feature de IA no es una sola decisión ("¿a qué modelo la mando?"); es un recorrido por varias estaciones, y en cada una puede resolverse o pasar a la siguiente —como un trámite bien diseñado que resuelve la mayoría de los casos en la primera ventanilla y solo manda a la ventanilla especializada los que de verdad la necesitan—.

La primera estación es la caché: "¿ya respondí esto antes?". Si sí (un hit), la petición termina aquí, gratis y al instante —ni siquiera toca el LLM—. Este es el filtro más poderoso, y por eso va primero: elimina el grueso del tráfico repetido antes de gastar un centavo. La mayoría de las peticiones de un sistema real ni pasan de esta ventanilla.

La segunda estación, solo para los misses, es el cascade: "esta petición es nueva, ¿la resuelve el barato o necesita el caro?". El clasificador enruta —fácil al cheap, difícil al strong— y aquí sí se llama al LLM, pero al modelo más pequeño que alcance. Solo las peticiones que sobrevivieron a la caché y que el clasificador juzga difíciles llegan al modelo caro. Es una fracción pequeña del tráfico total.

Y sobre todo el recorrido está la compuerta del presupuesto: al final, ¿el resultado cabe en el latency budget y el cost budget? Si genera texto que el usuario espera, se sirve con streaming para respetar el presupuesto de latencia percibida. El presupuesto es el inspector que verifica que el trámite completo —caché + cascade + entrega— cumple las dos reglas que la lección 3 fijó.

El orden importa, y no es arbitrario. La caché va primero porque es la que más tráfico elimina y la más barata de consultar: no tiene sentido clasificar y enrutar una query que ya tienes respondida. El cascade va segundo porque opera sobre lo que la caché no atrapó. Y el presupuesto envuelve todo porque es la razón de ser del recorrido. Esta lección es aprender a dibujar ese camino y a medir que, recorrido en ese orden, mete la feature en su presupuesto.

Ejemplo trabajado: componer sobre el agente de soporte

Vamos a componer las técnicas sobre el agente de soporte de Mercado —distinto a la búsqueda de las lecciones anteriores— y a medir cada combinación contra su presupuesto. El agente es conversacional: las preguntas frecuentes (FAQ) se repiten mucho (buenas para caché), y su dificultad varía (buenas para cascade). El workload son 3000 turnos, de 200 FAQ con popularidad Zipf más un 25% de cola larga (preguntas nuevas y difíciles). El 30% de las FAQ son difíciles. El clasificador acierta el 92%.

El presupuesto del agente: $5,000/mes a 30,000 turnos/día. Medimos cuatro estrategias —naive (todo al caro), solo caché, solo cascade, y caché+cascade— y vemos cuál cabe.

# Leccion 07 — el camino de la peticion consciente del costo (cache + cascade + budget)
# Aplicado al agente de soporte de Mercado. Todo SIMULADO. Semilla fija.
import random

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]
    return m["base_ms"] + out_tokens * m["ms_per_tok"], \
           (in_tokens/1000)*m["usd_in"] + (out_tokens/1000)*m["usd_out"]

IN_TOK = 300
OUT_EASY, OUT_HARD = 120, 300
HIT_MS, HIT_COST = 2.0, 0.0
CLASSIFIER_MS = 3

# --- El PRESUPUESTO del agente de soporte ---
MONTHLY_COST_BUDGET = 5000.0
TURNS_PER_DAY = 30_000

# --- El workload: 3000 turnos. Preguntas frecuentes (se repiten) + cola larga unica. ---
random.seed(23)
N = 3000
POOL = [f"faq_{i:03d}" for i in range(200)]
WEIGHTS = [1.0/(i+1) for i in range(200)]
DIFFICULTY = {faq: (random.random() < 0.30) for faq in POOL}   # 30% de las FAQ son dificiles

_uid = [0]
def make_turn():
    if random.random() < 0.25:                       # cola larga: pregunta nueva y dificil
        _uid[0] += 1
        return (f"novel_{_uid[0]}", True)            # (texto, es_dificil)
    faq = random.choices(POOL, weights=WEIGHTS, k=1)[0]
    return (faq, DIFFICULTY[faq])
turns = [make_turn() for _ in range(N)]

def out_for(hard): return OUT_HARD if hard else OUT_EASY
def classify(hard): return hard if random.random() < 0.92 else (not hard)

def run(use_cache, use_cascade):
    cache = set()
    cost, lats = 0.0, []
    for text, hard in turns:
        if use_cache and text in cache:
            cost += HIT_COST; lats.append(HIT_MS); continue
        if use_cache:
            cache.add(text)
        if use_cascade:
            model = "strong" if classify(hard) else "cheap"
            extra = CLASSIFIER_MS
        else:
            model, extra = "strong", 0.0
        lat, c = call_llm(model, IN_TOK, out_for(hard))
        cost += c; lats.append(lat + extra)
    return cost, sum(lats)/len(lats)

def monthly(cost_per_run):
    return cost_per_run * (TURNS_PER_DAY * 30 / N)

def verdict(m): return "OK   " if m <= MONTHLY_COST_BUDGET else "VIOLA"

print(f"{'strategy':<20}{'total_cost':>12}{'avg_lat_ms':>12}{'monthly_usd':>13}{'budget':>8}")
for label, uc, ucas in (("all_strong", False, False),
                        ("cache_only", True, False),
                        ("cascade_only", False, True),
                        ("cache+cascade", True, True)):
    cost, avg = run(uc, ucas)
    mo = monthly(cost)
    print(f"{label:<20}{cost:>12.4f}{avg:>12.1f}{mo:>13,.0f}{verdict(mo):>8}")

print(f"\nmonthly_cost_budget = ${MONTHLY_COST_BUDGET:,.0f}/mes   ({TURNS_PER_DAY:,} turnos/dia)")

Qué esperar. Al correrlo:

strategy              total_cost  avg_lat_ms  monthly_usd  budget
all_strong               30.9168       892.9        9,275   VIOLA
cache_only               12.9888       364.8        3,897   OK   
cascade_only             19.4083       588.9        5,822   VIOLA
cache+cascade            11.3818       323.7        3,415   OK   

monthly_cost_budget = $5,000/mes   (30,000 turnos/dia)

Esta tabla es el módulo entero condensado. Léela fila por fila, porque cada una enseña algo.

Naive (todo al caro): $9,275/mes — VIOLA. El punto de partida ingenuo, el que la lección 1 llamó "es solo otra llamada a una API": cada turno al strong model. Cuesta casi el doble del presupuesto de $5,000. Es la línea base contra la que se mide todo lo demás.

Solo caché: $3,897/mes — OK. La caché sola, sin cascade, ya mete la feature en el presupuesto. Recorta 58% del costo ($30.92 → $12.99 por 3000 turnos) porque elimina el tráfico repetido de las FAQ —el grueso de las conversaciones de soporte son preguntas frecuentes—. Fíjate: la caché sola cabe ($3,897 < $5,000), pero al borde: le queda poco headroom antes del presupuesto.

Solo cascade: $5,822/mes — VIOLA. El cascade solo, sin caché, recorta 37% ($30.92 → $19.41) enrutando lo fácil al barato. Es una mejora grande… pero no alcanza: $5,822 sigue por encima del presupuesto de $5,000. Esta fila es la más importante de la tabla, porque es contraintuitiva: una técnica poderosa, bien aplicada, y aun así viola el presupuesto. El cascade solo no basta para el agente de soporte. Quien concluyera "metimos cascade, ya está" habría dejado la feature fuera de presupuesto sin darse cuenta.

Caché + cascade: $3,415/mes — OK, con holgura. Las dos juntas recortan 63% ($30.92 → $11.38) y dejan la feature en $3,415/mes —bien debajo de los $5,000, con headroom real para crecer—. Esta es la arquitectura que se lleva a producción: no la que apenas cabe, sino la que cabe con margen.

Ahora, la lección que estos números enseñan y que casi nadie ve: las técnicas se acumulan pero NO suman. Mira: la caché sola ahorra 58%, el cascade solo ahorra 37%. Si sumaras, esperarías 58 + 37 = 95% de ahorro. Pero la combinación ahorra solo 63%, no 95%. ¿Por qué? Porque se solapan sobre el mismo tráfico. La caché ya eliminó el 58% del tráfico (las FAQ repetidas, que además son mayormente fáciles); cuando el cascade llega, solo le quedan los misses —la cola larga difícil y las primeras ocurrencias—, que son más orientados al strong model y donde el cascade ahorra menos. La caché se comió el tráfico fácil/repetido que el cascade también habría abaratado, así que la ganancia del cascade encima de la caché es modesta ($12.99 → $11.38, ~12% adicional). Las palancas no son independientes: atacan tráfico solapado, y por eso hay que medir la combinación real, no sumar los ahorros por separado.

El presupuesto como el que ordena. Fíjate en el rol del presupuesto en toda esta historia: es la línea que decide qué combinación es "suficiente". Sin el presupuesto de $5,000, no sabrías si el cascade solo (que ahorra un impresionante 37%) es aceptable —y no lo es—. El presupuesto es lo que convierte "ahorré mucho" en "cumplo o no cumplo". Y para tener holgura frente al crecimiento del tráfico (recuerda de la lección 3 que el veredicto depende del volumen, y el volumen sube con el éxito), se elige la combinación con más margen: caché + cascade, no caché sola al borde.

Profundización: el orden, la latencia, y qué falta en la tabla

Por qué caché primero, cascade después. El orden del recorrido no es casual. La caché va primero porque (a) es la que más tráfico elimina —el grueso, gratis— y (b) consultarla es casi instantáneo, así que filtrar temprano no cuesta nada. No tendría sentido clasificar la dificultad de una query y elegir modelo para una petición que ya tienes respondida en caché: sería trabajo desperdiciado antes de darte cuenta de que no hacía falta llamar a nadie. El cascade va después porque opera sobre lo que la caché no atrapó —el tráfico genuinamente nuevo—, y ahí sí decide barato vs caro. El principio general: pon primero el filtro más barato y de mayor rendimiento. La caché es ese filtro.

La latencia también mejoró, y ahí está el streaming. Mira la columna avg_lat_ms: naive 893 ms, caché+cascade 324 ms —la latencia promedio bajó junto con el costo, porque los hits salen en 2 ms y las fáciles en 150—. Pero recuerda la lección 4: la latencia promedio no es la de cola. Las peticiones difíciles que llegan al strong model siguen tardando ~1200 ms, y para esas —si generan texto que el usuario espera en vivo, como en el agente de soporte— el camino se completa con streaming (lección 6): el usuario ve el primer token a los ~300 ms aunque la respuesta completa tarde más. Así el camino consciente del costo respeta las dos dimensiones del presupuesto: el costo (caché + cascade) y la latencia percibida (streaming en la cola). La compuerta del presupuesto verifica las dos.

Qué falta en esta tabla: la calidad. La tabla mide costo y latencia —las dos restricciones de este módulo— y muestra que caché+cascade las respeta. Pero no mide la tercera compuerta: ¿las respuestas siguen siendo buenas? El cascade manda las fáciles al cheap model y la caché sirve respuestas guardadas; las dos decisiones podrían, mal calibradas, degradar la calidad (un cheap model que responde peor, una caché que sirve algo viejo o que no corresponde). Verificar que el ahorro no vino a costa de la calidad es el eval gate, todo el módulo 3. El camino completo de una feature de IA en producción tiene las tres compuertas: cost budget (aquí), latency budget (aquí), y quality gate (módulo 3). Esta lección compone las dos primeras; la tercera es tan obligatoria como estas.

Componer no es opcional a alto volumen. Un patrón que la tabla deja claro: a medida que el volumen y el costo crecen, ninguna técnica sola alcanza, y componer deja de ser una optimización para volverse una necesidad. En el agente de soporte, el cascade solo violaba el presupuesto; hizo falta la caché encima. En otra feature podría ser al revés (la caché sola no alcanza y hace falta el cascade). Y en una tercera, ni las dos juntas bastan y hay que sumar más —limitar la longitud de las respuestas, meter un tercer nivel de modelo, un TTL más agresivo—. La regla no es "aplica esta técnica"; es "mide contra el presupuesto y compón lo que haga falta hasta caber con holgura". El presupuesto dice cuánto es suficiente; las técnicas son las palancas para llegar ahí.

Errores comunes

Creer que una sola técnica basta (de bala de plata). Qué pasa: el equipo mete cascade (o caché) sola, ve un ahorro grande, y da por resuelto el presupuesto —sin verificar si de verdad cabe—. En el agente de soporte, el cascade solo ahorra 37% impresionante… y aun así viola el presupuesto. La feature sale a producción sobre presupuesto sin que nadie lo note. Por qué pasa: cada técnica da un ahorro visible y satisfactorio, y es fácil detenerse en la primera. Cómo detectarlo: si aplicaste una técnica pero no volviste a pesar el resultado contra el presupuesto, no sabes si cabe. Cómo corregirlo: después de cada técnica, corre la compuerta del presupuesto; si viola, compón la siguiente —el presupuesto, no el ahorro, dice cuándo terminaste—.

Sumar los ahorros por separado (de aritmética falsa). Qué pasa: se estima el ahorro combinado sumando el de cada técnica —"la caché ahorra 58%, el cascade 37%, juntas 95%"— y se planea el presupuesto sobre ese 95% inflado. La realidad (63%) llega corta, y la feature no cabe donde se prometió. Por qué pasa: sumar es la operación intuitiva, y esconde que las técnicas se solapan sobre el mismo tráfico barato. Cómo detectarlo: si tu estimación del ahorro combinado es la suma de los ahorros individuales, sobrestimaste. Cómo corregirlo: mide la combinación ejecutándola, no sumando —caché+cascade juntas, sobre el workload real, dan el número verdadero, casi siempre menor que la suma—.

Componer en el orden equivocado (de recorrido). Qué pasa: se pone el cascade antes que la caché —se clasifica y se elige modelo, y luego se revisa si estaba en caché—, desperdiciando el trabajo de clasificar peticiones que ya estaban respondidas. Es correcto en resultado pero ineficiente, y en una feature de mucho volumen esa ineficiencia se acumula. Por qué pasa: se ensamblan las técnicas en el orden en que se aprendieron o se implementaron, no en el orden en que conviene ejecutarlas. Cómo detectarlo: si tu camino hace trabajo (clasificar, llamar) antes de consultar la caché, el orden está invertido. Cómo corregirlo: pon primero el filtro más barato y de mayor rendimiento —la caché— y solo lo que sobreviva pasa al cascade.

Ejercicios

Ejercicio 1 — ¿Por qué 63% y no 95%? Explica con tus palabras, sin correr código, por qué la caché (58% de ahorro sola) y el cascade (37% solo) combinados dan 63% y no 95%. Usa la idea de "tráfico solapado".

Ver solución

Los ahorros no suman porque las dos técnicas atacan tráfico que se solapa, no tráfico independiente.

La caché ahorra eliminando el tráfico repetido —las FAQ que se preguntan una y otra vez—. Ese tráfico repetido tiende a ser, además, el tráfico fácil (las preguntas comunes suelen ser las simples). Cuando la caché ya se comió ese 58%, lo que le queda al cascade son los misses: la cola larga difícil y las primeras ocurrencias de cada FAQ —tráfico más único y más orientado al strong model, justo donde el cascade ahorra menos (porque menos de ese tráfico es "fácil" para mandar al barato)—.

Dicho de otro modo: si el cascade operara sobre el 100% del tráfico, ahorraría 37% mandando el ~70% fácil al barato. Pero no opera sobre el 100%: opera sobre el ~42% que la caché no atrapó, y de ese 42% una porción mayor es difícil. Así que el cascade encima de la caché solo agrega ~12% ($12.99 → $11.38), no 37%. La caché ya "gastó" el tráfico fácil/repetido que el cascade también habría abaratado.

La moraleja: cuando dos optimizaciones atacan el mismo tráfico, sus ahorros se solapan y no se suman. La única forma de saber el ahorro combinado real es medir la combinación ejecutándola —que es exactamente lo que hace la tabla—.

Ejercicio 2 — El agente crece. El agente de soporte de Mercado es un éxito y su tráfico sube de 30,000 a 80,000 turnos/día. Con el mismo presupuesto de $5,000/mes, ¿qué estrategias siguen cabiendo? (Usa los total_cost por 3000 turnos de la tabla: naive 30.9168, cache_only 12.9888, cascade_only 19.4083, cache+cascade 11.3818. El mensual es total_cost × (80000 × 30 / 3000).)

Ver solución

El factor de escala es 80000 × 30 / 3000 = 800. Multiplicamos cada total_cost por 800:

  • naive: 30.9168 × 800 = $24,733/mes → VIOLA (por mucho).
  • cache_only: 12.9888 × 800 = $10,391/mes → VIOLA. ¡La caché sola, que a 30k/día cabía ($3,897), ahora viola el presupuesto!
  • cascade_only: 19.4083 × 800 = $15,527/mes → VIOLA.
  • cache+cascade: 11.3818 × 800 = $9,105/mes → VIOLA. Incluso la combinación viola a este volumen.

A 80,000 turnos/día, ninguna de las cuatro cabe en $5,000. La lección es doble:

  1. El headroom importa. A 30k/día, la caché sola cabía pero al borde ($3,897 de $5,000); en cuanto el tráfico casi se triplicó, se salió. La combinación caché+cascade cabía con más holgura ($3,415), y aguantó más antes de salirse —pero también se salió—. Elegir la opción con más margen no es lujo: es lo que da tiempo de reaccionar al crecimiento.
  2. A veces hay que sumar más técnicas, o subir el presupuesto. Cuando el volumen crece tanto que ni caché+cascade alcanza, las opciones son: componer aún más (limitar la longitud de las respuestas para bajar el costo por llamada, un TTL de caché más agresivo, un tercer nivel de modelo), o renegociar el cost budget con el negocio (si la feature genera suficiente valor para justificar más gasto). El presupuesto no es sagrado si el negocio lo revisa; pero la arquitectura tiene que caber en el número acordado.

Ejercicio 3 — Dibuja el camino. Dibuja (en ASCII o mermaid) el camino de una petición del agente de soporte pasando por caché → cascade → presupuesto → entrega, marcando dónde puede terminar temprano (hit) y dónde se decide barato vs caro. Luego di en qué punto entraría el eval gate del módulo 3.

Ver solución
flowchart TD
    A[Peticion del usuario] --> B{Cache: ya la respondi?}
    B -- HIT --> C[Servir respuesta guardada<br/>~2 ms, $0]
    B -- MISS --> D{Clasificador: facil o dificil?}
    D -- facil --> E[cheap model<br/>~150 ms, barato]
    D -- dificil --> F[strong model<br/>~1200 ms, caro]
    E --> G[Guardar en cache]
    F --> G
    G --> H{Compuerta de presupuesto<br/>cabe en latency + cost budget?}
    H -- genera texto en vivo --> I[Entregar con streaming<br/>TTFT ~300 ms]
    H -- resultado directo --> J[Entregar]

Notas del camino:

  • Termina temprano en el HIT (arriba a la izquierda): la mayoría de las peticiones ni tocan el LLM. Es el filtro de mayor rendimiento, por eso va primero.
  • Barato vs caro se decide en el clasificador (solo para los misses): fácil → cheap, difícil → strong.
  • El presupuesto envuelve el final: verifica costo y latencia; si genera texto que el usuario espera en vivo, entrega con streaming para respetar el latency budget en la cola.

Dónde entra el eval gate (módulo 3): el eval no vive en el camino de la petición en tiempo real —no se corre en cada petición—; vive antes, en el diseño y en CI, verificando que las decisiones del camino no degradan la calidad. Concretamente, el eval gate verifica dos cosas de este diagrama: (1) que las respuestas del cheap model para las queries enrutadas como "fáciles" son lo bastante buenas (que el cascade no sacrificó calidad al abaratar), y (2) que las respuestas cacheadas siguen siendo válidas (que el TTL y la clave de caché no sirven algo viejo o que no corresponde). Si un cambio de prompt o de modelo baja el score del eval-set, el eval gate bloquea el deploy —así el camino consciente del costo nunca sale a producción con calidad rota—. Las tres compuertas juntas —cost budget, latency budget, quality gate— son lo que hace segura una feature de IA.

Resumen y siguiente paso

En esta lección compusiste las cuatro piezas del módulo en un solo camino de la petición consciente del costo: caché primero (¿ya la tengo?), cascade después (¿barato o caro?), con el presupuesto como compuerta y el streaming para la latencia de cola. Con la fila de varias ventanillas viste por qué el orden importa —el filtro más barato y de mayor rendimiento (la caché) va primero—. Y con la tabla ejecutada sobre el agente de soporte mediste la lección central: naive $9,275/mes (viola), caché sola $3,897 (cabe al borde), cascade solo $5,822 (viola —una técnica poderosa que aun así no basta), y caché+cascade $3,415 (cabe con holgura). Aprendiste que las técnicas se acumulan pero no suman (58% + 37% dan 63%, no 95%, porque se solapan sobre el tráfico barato), que el presupuesto es lo que decide cuándo una combinación es suficiente, que se elige la opción con headroom para aguantar el crecimiento, y que falta una tercera compuerta —la calidad, el eval gate del módulo 3—.

Antes de avanzar deberías poder: dibujar el camino de una petición (caché → cascade → presupuesto → entrega) y explicar por qué ese orden; componer las técnicas y medir la combinación real en vez de sumar ahorros; reconocer que ninguna técnica sola basta a alto volumen; y ubicar dónde entra el eval gate en el diseño completo.

Lo que sigue es hacerlo tú, de cero. En la lección 8 —el proyecto— vas a diseñar el presupuesto de una feature de IA de Mercado distinta a la de esta lección (la búsqueda semántica), y a armar su camino consciente del costo con tus manos: fijar el latency y cost budget, componer cascade + caché, medir contra el naive, justificar por qué la feature cabe en su presupuesto, y decidir dónde va el streaming. Es la síntesis del módulo aplicada por ti a un caso nuevo —la prueba de que aprendiste el método y no memorizaste una tabla—.

Recursos