Deriva de proveedor: cómo el enrutamiento predeterminado dispara el coste de los LLM
Contenido
Has activado el prompt caching y el contador de aciertos aumenta de vez en cuando, pero la factura apenas cambia. Antes de culpar a la estructura del prompt, revisa un dato que el dashboard no muestra: qué upstream atendió realmente cada solicitud.
Los gateways multiproveedor distribuyen un mismo modelo entre varios proveedores upstream y eligen uno para cada solicitud. Las prompt caches son independientes por proveedor y, a menudo, incluso por nodo dentro del mismo proveedor. Si la segunda solicitud idéntica llega a un upstream distinto del primero, se produce un fallo de caché aunque el prompt no haya cambiado ni un byte. Esto es la deriva de proveedor y, con un modelo de pago por token, multiplica el coste sin que resulte evidente.
TL;DR
- Con el enrutamiento configurado de fábrica, un gateway multiproveedor repartió 20 llamadas idénticas entre 9 upstreams y solo acertó en la prompt cache 4 veces de 20.
- Un gateway con un único backend obtuvo 19/20 aciertos con la misma carga; la deriva hizo que la ejecución costara unas 3.9x más ($0.0102 frente a $0.0026).
- En el modelo de la familia DeepSeek analizado, un fallo de caché costó unas 4x más que un acierto ($0.00062 frente a una mediana de $0.00015 por llamada).
- La deriva depende del modelo: el mismo gateway dirigió un modelo de la clase GPT a un único upstream durante las 20 llamadas y obtuvo 19/20 aciertos.
Las dos condiciones que la provocan
No es una configuración errónea que hayas activado. Es el comportamiento inicial:
- Enrutamiento automático predeterminado. La solicitud se envía al modelo sin fijar un upstream, por lo que el gateway elige uno en cada llamada.
- Orden predeterminado de proveedores = “default (balanced)”. El gateway balancea la carga entre los upstreams disponibles en lugar de mantener uno fijo.
Ambos son los valores de fábrica. No tienes que cambiar nada para que aparezca la deriva; tienes que modificar la configuración para evitarla.
Cómo se ven 20 solicitudes idénticas
Enviamos exactamente el mismo prefijo de unos 8K tokens 20 veces seguidas a un conocido gateway multiproveedor con la configuración predeterminada anterior. En cada llamada pedimos los campos de proveedor y caché que reportaba el propio upstream. Para un modelo de la familia DeepSeek con caché en disco:
- 9 upstreams distintos atendieron las 20 llamadas:
N***a,S***w,M***h,D***a,A***L,P***l,S***e,V***e,A***d. - Tasa de aciertos de caché: 4/20 (20%). Solo hubo acierto cuando una llamada cayó por casualidad en un upstream que ya tenía el prefijo en caché.
Al ejecutar las mismas 20 llamadas contra un gateway con un único backend —un modelo, un upstream y sin balanceo—, la misma carga alcanza una tasa de aciertos de 19/20 (95%). Mismo modelo, mismo prompt y mismo número de llamadas. La única variable es si el enrutamiento cambia de upstream.
Como contraste, en ese mismo gateway multiproveedor, un modelo de la clase GPT se dirigió a un solo upstream (A***e) durante las 20 llamadas y logró 19/20 aciertos. La deriva no afecta por igual a todos los modelos. Perjudica a los que el gateway distribuye entre varios upstreams; en esta ejecución fue el modelo de la familia DeepSeek.
Conclusión A: el coste esperado frente al coste real
El coste por llamada del modelo afectado por la deriva quedó claramente dividido según el resultado de la caché:
| tipo de llamada | coste mediano por llamada |
|---|---|
| acierto de caché | ~$0.00015 |
| fallo de caché | ~$0.00062 |
En este modelo, un fallo cuesta unas 4x más que un acierto. La diferencia publicada para los tokens de entrada sin procesar es aún mayor, de aproximadamente 50x. Sumemos ahora las 20 llamadas:
| escenario | tasa de aciertos | coste de 20 llamadas idénticas |
|---|---|---|
| esperado (caché accesible) | 95% | $0.0026 |
| real (deriva predeterminada) | 20% | $0.0102 |
Mismo modelo, mismo prompt y las mismas 20 solicitudes. La deriva de proveedor hizo que la ejecución costara ~3.9x más. La caché estuvo «activada» todo el tiempo, pero la capa de enrutamiento facturó la mayoría de los tokens al precio de un fallo. En un endpoint de producción que reutiliza durante todo el día un prefijo grande y estable, esa diferencia representa la mayor parte del gasto en tokens de entrada.
Conclusión B: sin caché tampoco mejora la latencia
La caché no solo reduce costes. Con un prefill caliente, el primer token llega antes. Cuando la deriva impide acceder a la caché, también se pierde esa mejora. Medimos el tiempo hasta el primer token (TTFT) en llamadas idénticas repetidas:
Modelo de la clase GPT (dirigido siempre al mismo upstream, con la caché accesible):
| llamada | TTFT |
|---|---|
| 1.ª (fría, fallo) | ~1760 ms |
| posteriores (calientes, acierto) | ~1130 ms |
La caché adelanta el primer token aproximadamente un 36% y lo hace de forma estable: todas las llamadas calientes quedan dentro de un intervalo estrecho.
Modelo de la familia DeepSeek (deriva predeterminada, caché casi nunca accesible):
- Aciertos de caché en una repetición de 10 llamadas: 0.
- El TTFT osciló entre ~1000 ms y ~4500 ms de una llamada a otra, con alguna respuesta vacía.
Como casi todas las solicitudes llegan a un upstream nuevo, la latencia se mantiene en niveles de prefill frío y además incorpora la variabilidad del proveedor que responda. El modelo GPT redujo el TTFT un 36% gracias a una caché accesible. El modelo afectado por la deriva no obtuvo ninguna mejora y mostró una diferencia de 4.5x entre la llamada más rápida y la más lenta.
Audita tu configuración en cinco minutos
No te fíes de estas cifras ni de las de nadie. Envía varias veces el mismo prefijo largo y observa dos campos. No hay dominios hardcodeados: usa variables de entorno para apuntar a tu propio gateway.
import os, uuid
from openai import OpenAI
client = OpenAI(api_key=os.environ["GW_KEY"], base_url=os.environ["GW_BASE"])
SYS = f"[probe {uuid.uuid4().hex}]\n\n" + ("You are a support assistant. " * 300)
seen, hits = {}, 0
for i in range(20):
r = client.chat.completions.create(
model=os.environ["GW_MODEL"], max_tokens=16,
messages=[{"role": "system", "content": SYS},
{"role": "user", "content": f"q{i}"}],
extra_body={"usage": {"include": True}})
d = r.model_dump()
det = r.usage.prompt_tokens_details
cached = (getattr(det, "cached_tokens", 0) or 0) if det else 0
seen[d.get("provider")] = seen.get(d.get("provider"), 0) + 1 # populated when exposed
hits += 1 if cached else 0
print(f"hit rate {hits}/20; upstreams seen: {len(seen)}")
Si aparece más de un upstream para el mismo modelo, hay deriva. Si la tasa de aciertos es muy inferior a la estabilidad de tus prompts, estás pagando el sobrecoste. El método completo está en ¿Tu gateway de LLM miente sobre la caché?.
En qué fijarse
La solución a la deriva es estructural: dirige cada modelo a un backend estable para que la caché caliente siga accesible en la siguiente solicitud. No balancees cada llamada hacia un upstream nuevo que nunca haya visto el prefijo. Al evaluar un gateway, envía el mismo prefijo 20 veces y cuenta los upstreams. Uno es lo deseable. Nueve es un impuesto.
Hay una salvedad: el prompt caching funciona en modo best-effort en todas partes. En los modelos con caché en disco, la tasa de aciertos también disminuye tras largos periodos de inactividad, incluso con un único backend. Eliminar la deriva no proporciona una caché infinita. Sí elimina la mayor fuente de fallos y la más costosa: una que no has aceptado y que no puedes ver.
Cierre
«Admite prompt caching» y «tu caché es accesible» son afirmaciones distintas. Un gateway que reparte un modelo entre un conjunto rotativo de upstreams puede afirmar con razón que admite caché y, aun así, ofrecer una tasa de aciertos del 20%, una factura ~4x mayor y una latencia del primer token con variaciones de 4.5x. No debes vigilar si se anuncia soporte de caché, sino la tasa de aciertos medida y el número de upstreams que reciben tus solicitudes idénticas. Ejecuta la prueba y deja que los datos decidan.
Para consultar el método de auditoría completo, lee ¿Tu gateway de LLM miente sobre la caché?. Para entender por qué existen estas cachés, consulta Cómo funcionan la KV cache y el TTL.
Preguntas frecuentes
¿Es una configuración errónea por mi parte? No. Ocurre con los valores de fábrica: enrutamiento automático y el orden de proveedores configurado como “default (balanced).” Para evitar la deriva hay que fijar un upstream de forma explícita, no al revés.
¿Se soluciona fijando un único upstream? Se elimina la deriva entre proveedores, pero un único upstream suele ejecutar varias réplicas sin afinidad de prefijo, por lo que los aciertos pueden seguir siendo intermitentes. Mídelo después de fijarlo en lugar de darlo por hecho.
¿Por qué no hubo deriva en el modelo de la clase GPT? En esta ejecución, el gateway lo dirigió por casualidad a un único upstream. La deriva depende de cada modelo y del número de upstreams disponibles entre los que el gateway balancea la carga; no es uniforme.
¿La diferencia de coste es realmente de ~4x? Según los costes totales por llamada que medimos, un fallo costó ~4x más que un acierto. En la tarifa publicada para tokens de entrada sin procesar de esta clase de modelo, la diferencia entre acierto y fallo se acerca a 50x. En ambos casos, lo caro es convertir los aciertos esperados en fallos.
¿Qué única métrica debería monitorizar? La tasa de aciertos de caché por modelo a lo largo del tiempo, junto con el número de upstreams distintos por modelo. Si la tasa de aciertos baja o aumenta el número de upstreams, tu coste efectivo por token acaba de subir.