Coste y límites: neurons, rate limits y cuándo salir fuera
Workers AI no factura por tokens sino por neurons, una unidad abstracta que pone en la misma escala a un embedding, una transcripción y una imagen generada. Qué mide realmente esa unidad y cómo estimar lo que costará una función antes de escribirla, qué límites de peticiones por minuto y de tamaño de entrada gobiernan cada modelo y cómo absorber un `429` sin romper la experiencia, y el criterio honesto para decidir cuándo el catálogo se queda corto y conviene llamar a un proveedor externo, con AI Gateway delante.
La pregunta que decide si un proyecto con IA sobrevive al contacto con la realidad no es cuál es el mejor modelo, sino cuánto cuesta cada invocación y cuántas caben por minuto. Workers AI responde a la primera con una unidad propia, el neuron, que unifica modalidades que de otro modo serían incomparables; y a la segunda con límites por modelo que conviene conocer antes de que un pico de tráfico te los enseñe. Y cuando ninguna de las dos respuestas encaja con lo que necesitas, existe una tercera decisión perfectamente legítima: salir de la plataforma, con criterio.
- Entender qué es un neuron y por qué unifica modalidades que no se pueden comparar por tokens.
- Estimar el coste de una función de IA antes de escribirla y acotarlo por diseño.
- Conocer los límites de peticiones por minuto y absorber un
429sin romper la experiencia. - Decidir con criterio cuándo el catálogo se queda corto y conviene un proveedor externo.
Neurons: una unidad para modalidades incomparables
Facturar por tokens funciona mientras todo sea texto, y se rompe en cuanto no lo es. ¿Cuántos tokens tiene una imagen generada? ¿Y un minuto de audio transcrito? ¿Cómo se compara un embedding de un párrafo con seiscientas palabras redactadas por un modelo de setenta mil millones de parámetros? Los tokens no sirven como moneda común porque no significan lo mismo en cada modalidad.
El neuron resuelve eso convirtiéndose en una medida de trabajo de GPU, no de contenido. Cada modelo tiene una tarifa expresada en neurons por unidad de su propia modalidad: neurons por millón de tokens de entrada y de salida en los modelos de texto, neurons por segundo de audio en la transcripción, neurons por imagen o por paso de difusión en la generación visual. La consecuencia práctica es que un único número resume el gasto de un sistema que mezcla cuatro tipos de inferencia distintos, y que puedes comparar directamente lo que te cuesta indexar un corpus con lo que te cuesta contestar una pregunta.
Sobre esa unidad se monta un modelo de facturación de asignación diaria más excedente: hay una cantidad de neurons incluida cada día, y a partir de ahí se cobra por cada mil neurons consumidos. El plan gratuito ofrece esa asignación diaria como techo duro, lo que lo hace excelente para prototipar y desaconsejable para producción, porque agotarla significa quedarse sin inferencia hasta el día siguiente. Verifica siempre las cifras vigentes en la documentación antes de construir un presupuesto sobre ellas.
Lo que sí conviene interiorizar, más allá de las cifras concretas, son los órdenes de magnitud relativos entre familias, porque son bastante estables y determinan el diseño mucho antes que el precio exacto.
| Familia | Qué se mide | Coste relativo por invocación |
|---|---|---|
| Embeddings | Tokens de entrada | Bajísimo: indexar miles de fragmentos cuesta poco |
| Modelos utilitarios | Tokens de entrada y salida | Muy bajo: clasificar o traducir es casi gratis |
| LLM pequeño | Tokens de entrada y salida | Bajo, y dominado por la longitud de la salida |
| LLM grande | Tokens de entrada y salida | Un orden de magnitud por encima del pequeño |
| Transcripción | Segundos de audio | Moderado, y proporcional a la duración |
| Difusión | Imágenes | pasos de generación | Alto: la modalidad más cara con diferencia |
Leer esa tabla con atención evita los dos errores de presupuesto más caros que se cometen al empezar. El primero es temer al coste de los embeddings y acabar recuperando peor de lo necesario: indexar es barato, y casi siempre merece la pena trocear fino y guardar de más. El segundo es tratar la generación de imágenes como una llamada más dentro de un manejador fetch, cuando su perfil de coste y latencia pide a gritos vivir en una cola con notificación posterior.
Coge tu función de IA y calcula a mano: tokens de entrada por invocación más tokens de salida, multiplicado por la tarifa del modelo, multiplicado por invocaciones diarias esperadas. Es una cuenta de dos minutos que te dirá si tu idea cuesta céntimos o cientos de euros al mes, y suele revelar algo incómodo y muy útil: que el prompt de sistema de cuatrocientos tokens que envías en cada llamada pesa más en la factura que la respuesta, o que un historial de conversación sin truncar convierte una función barata en una que crece con cada turno.
Las palancas para bajar ese número son casi siempre las mismas cuatro, y ninguna requiere renunciar a nada esencial. Elegir el modelo más pequeño que resuelva la tarea es la que más ahorra, con diferencia de un orden de magnitud. Poner un max_tokens ajustado impide que una respuesta se vaya por las ramas a tu costa. Recortar el contexto —truncar el historial, no inyectar documentos enteros cuando basta un fragmento— ataca la entrada, que en las tareas de tipo RAG suele dominar el gasto. Y cachear las respuestas de peticiones repetidas convierte una inferencia en una lectura, que es gratis.
Los límites: peticiones por minuto y tamaño
Además del coste hay un techo de ritmo. Cada modelo tiene su propio límite de peticiones por minuto, y no es el mismo para todos: los modelos de embeddings, que son ligeros, admiten un caudal muy superior al de un modelo grande de texto o al de un difusor de imágenes, que ocupan la GPU durante mucho más tiempo por invocación. Cuando lo rebasas, la llamada devuelve un 429 y hay que estar preparado.
| Aspecto | Qué gobierna | Cómo se absorbe |
|---|---|---|
| Peticiones por minuto | Ritmo máximo por modelo y por cuenta | Reintento con espera creciente y algo de aleatoriedad |
| Tamaño de entrada | Límite de contexto y peso del audio o la imagen | Trocear el texto, partir el audio en segmentos |
| Concurrencia efectiva | Cuántas inferencias simultáneas sostienes | Diferir a Queues lo que no necesita respuesta inmediata |
| Modalidad pesada | Difusión | transcripción larga, muy costosas por llamada | Sacarlas del camino de la petición y notificar al terminar |
La forma correcta de absorber un 429 no es un reintento inmediato, que solo empeora la congestión, sino una espera que crece con cada intento y lleva un poco de ruido aleatorio para que mil clientes no reintenten a la vez.
async function inferir(env: Env, modelo: string, entradas: object, intentos = 3) {
for (let i = 0; i < intentos; i++) {
try {
return await env.AI.run(modelo, entradas);
} catch (error) {
const esRitmo = String(error).includes("429");
if (!esRitmo || i === intentos - 1) throw error;
const espera = 2 ** i * 250 + Math.random() * 200;
await new Promise((r) => setTimeout(r, espera));
}
}
}
Pero el patrón que de verdad escala no es reintentar más, sino no llamar tanto. Si la inferencia no tiene que ocurrir mientras alguien espera, sácala del camino de la petición: encola el trabajo, procésalo con el consumidor a un ritmo que tú controlas, y notifica al terminar. Una cola convierte un pico de tráfico que habría reventado el límite en una fila ordenada que lo respeta sin perder ni una tarea.
La segunda palanca es no repetir trabajo idéntico. Un porcentaje sorprendente de las inferencias de un sistema real son la misma entrada preguntada otra vez: la misma pregunta frecuente, el mismo documento reprocesado, el mismo texto clasificado dos veces por un reintento del cliente. Una caché con clave derivada del modelo y de las entradas convierte esas repeticiones en lecturas instantáneas y gratuitas, y de paso las saca de la cuenta del límite por minuto.
const clave = modelo + ":" + await hash(JSON.stringify(entradas));
const guardado = await env.CACHE_IA.get(clave, "json");
if (guardado) return guardado;
const salida = await env.AI.run(modelo, entradas);
ctx.waitUntil(env.CACHE_IA.put(clave, JSON.stringify(salida), { expirationTtl: 86400 }));
return salida;
Conviene aplicarla con cabeza: cachear tiene sentido cuando la misma entrada debe producir la misma salida, es decir, con temperature baja y tareas deterministas como clasificar, extraer o generar embeddings. Para una redacción creativa donde la variedad es parte del valor, la caché estropea el producto en lugar de mejorarlo.
Cuándo conviene un proveedor externo
Workers AI no es la respuesta a todo, y reconocer sus fronteras es señal de criterio y no de deslealtad. Hay cuatro situaciones en las que salir fuera es lo correcto: cuando necesitas la capacidad de razonamiento de un modelo de frontera que no está en el catálogo, cuando tu tarea exige una ventana de contexto muy superior a la que ofrecen los modelos disponibles, cuando dependes de capacidades específicas de un proveedor concreto, o cuando tienes un modelo propio entrenado desde cero que solo puede correr en tu infraestructura.
flowchart TD
N[Necesito inferencia] --> A{Esta la tarea cubierta por el catalogo}
A -->|Si| B{Basta la calidad del modelo disponible}
A -->|No| X[Proveedor externo via AI Gateway]
B -->|Si| W[Workers AI con binding]
B -->|No| C{Es critica esa diferencia}
C -->|No| W
C -->|Si| X
W --> G[AI Gateway para cache y observabilidad]
X --> G
style W fill:#a6e3a1,color:#11111b
style X fill:#fab387,color:#11111b
style G fill:#89b4fa,color:#11111bLa decisión, además, no es binaria y casi nunca debería serlo. Lo habitual en un sistema maduro es una arquitectura de dos niveles: los modelos pequeños del catálogo se ocupan del volumen —clasificar, extraer, generar embeddings, resumir, filtrar—, que es donde está el noventa por ciento de las invocaciones y donde el coste se acumula, y un modelo de frontera externo atiende la fracción minoritaria de peticiones que de verdad exigen su calidad. Eso mantiene la factura bajo control sin renunciar al techo de calidad donde importa.
La pieza que hace viable esa mezcla es AI Gateway, el tema del nivel siguiente. Puesto delante de ambos caminos te da caché de respuestas repetidas, límites de ritmo propios, reintentos, rutas de reserva hacia otro proveedor cuando uno falla, y una analítica unificada de coste y latencia. Con él, cambiar de proveedor deja de ser una reescritura y pasa a ser una configuración, que es exactamente donde quieres que viva una decisión que va a cambiar varias veces.
Observar el gasto antes de que te observe a ti
Un presupuesto estimado a mano sirve para decidir si una idea es viable; no sirve para saber qué está pasando en producción. Para eso hace falta instrumentar, y la instrumentación útil no mide el total —eso ya te lo dice el panel— sino la atribución: qué función de tu aplicación consume qué parte del gasto.
La forma más directa es registrar cada inferencia con las dimensiones que después querrás cruzar. Analytics Engine encaja bien aquí porque está pensado justo para esto: escrituras baratas desde el Worker, agregación después.
async function inferirMedido(env: Env, tarea: string, modelo: string, entradas: object) {
const inicio = Date.now();
const salida = await env.AI.run(modelo, entradas);
env.METRICAS.writeDataPoint({
blobs: [tarea, modelo], // por que funcion y con que modelo
doubles: [Date.now() - inicio], // cuanto tardo
indexes: [tarea], // la dimension por la que agregar
});
return salida;
}
Con eso puedes contestar preguntas que sin ellas son puras conjeturas: si el gasto se concentra en una funcionalidad que apenas usa nadie, si un cambio de modelo mejoró la latencia de verdad, si el pico del martes fue tráfico legítimo o un bucle mal cerrado, o si el prompt que alargaste la semana pasada duplicó el coste de la ruta más transitada.
Todo lo que un usuario puede invocar sin límite es una superficie de abuso. Un endpoint público que llama a un modelo por cada petición puede vaciar tu asignación diaria en minutos si alguien lo descubre, y la primera señal será que la funcionalidad deja de responder para todo el mundo. Pon un límite de ritmo por usuario o por dirección delante de la inferencia, valida el tamaño de la entrada antes de pagar por procesarla, y define qué debe ocurrir cuando el presupuesto se agota: degradar a un modelo más barato, servir una respuesta cacheada o desactivar la función es siempre mejor que caerse.
En el software tradicional aprendimos a razonar con una intuición muy concreta: el cómputo es prácticamente gratis y lo caro es el tiempo de la gente. Por eso resulta natural escribir un bucle que recorre diez mil filas sin pensarlo dos veces, o añadir una comprobación redundante porque total. La inferencia rompe esa intuición de raíz, porque devuelve al software algo que llevaba décadas sin tener: un coste marginal por operación que se siente. Cada llamada a un modelo cuesta dinero medible, tarda un tiempo perceptible y consume una capacidad finita, y eso convierte decisiones que antes eran puramente técnicas —¿lo hago en el camino de la petición o lo difiero?, ¿lo cacheo?, ¿uso el modelo grande o el pequeño?, ¿le paso el documento entero o solo el fragmento relevante?— en decisiones que tienen consecuencias económicas directas y visibles en una factura mensual. La consecuencia es que el coste unitario deja de ser un asunto de finanzas para convertirse en una restricción de diseño de primer orden, al mismo nivel que la latencia o la corrección, y hay que meterla en la conversación desde el primer boceto y no cuando llega el susto. Los sistemas de IA que envejecen bien comparten un mismo esqueleto, y no es casual: usan el modelo más pequeño que resuelve cada tarea en lugar del más impresionante disponible, cachean con obsesión porque una respuesta repetida no debería costar dos veces, difieren todo lo que nadie está esperando para desacoplar el pico de la capacidad, acotan por construcción cuánto puede consumir una sola invocación, y reservan la potencia cara para la fracción de casos que de verdad la justifican. Lo notable es que esa disciplina no es un mal necesario impuesto por el presupuesto: produce sistemas mejores por razones independientes del dinero, porque un modelo pequeño responde antes, una respuesta cacheada es instantánea, y un trabajo diferido sobrevive a un pico que habría tumbado al camino síncrono. Cuando la factura te obliga a diseñar bien, la factura estaba haciendo de arquitecto, y conviene escucharla temprano.
- Elige una función de IA de un proyecto tuyo y calcula a mano su coste diario en neurons con las tarifas vigentes del modelo.
- Repite el cálculo cambiando el modelo grande por uno pequeño y ajustando
max_tokens, y compara los dos totales. - Implementa el reintento con espera creciente y ruido aleatorio ante un
429, y verifica que tu endpoint sigue respondiendo bajo carga. - Coge una inferencia que hoy ocurre en el camino de la petición y muévela a una cola, notificando al terminar.
- Enumera las condiciones concretas bajo las que tu proyecto justificaría un proveedor externo, y diseña la arquitectura de dos niveles que las cubriría.