Cloudflare Workers AI a fondo: modelos de IA a una llamada de tu Worker

Qué es Workers AI y cómo funciona: un catálogo de modelos abiertos (texto, embeddings, imagen, voz) en GPUs de Cloudflare, con un binding en tu Worker o por API REST. Cómo se factura en neuronas, límites por tipo de modelo, streaming y un Worker de chat con tests.

Portada: Cloudflare Workers AI a fondo

Usar un modelo de lenguaje desde tu aplicación suele significar elegir entre dos males: pagar una API externa por token y mandarle tus datos, o montar tus propias GPUs. Workers AI es una tercera vía: un catálogo de modelos abiertos (Llama, Qwen, Mistral, gpt-oss, Gemma, Kimi y compañía, además de modelos de embeddings, imagen y voz) que Cloudflare ejecuta en GPUs de su red y que llamas con una línea desde un Worker.

No hay que desplegar nada, ni reservar máquinas, ni pagar por horas: pagas por uso, en una unidad propia llamada neurona, y tienes una cantidad gratis cada día incluso en el plan Free.

En este artículo vemos cómo funciona, cómo se factura (con cuentas reales), los límites, cómo hacer streaming y un Worker de chat con su manejo de errores.

🧪
Este artículo NO incluye inferencias reales. Workers AI no tiene simulación local: incluso con wrangler dev, cada llamada va a tu cuenta de Cloudflare y gasta neuronas, y no he usado una cuenta para estas pruebas. Lo que sí está comprobado, el 3 de octubre de 2026, con Wrangler 4.147.0, TypeScript 7.0.2 y Vitest 5.0.3: el código compila contra los tipos oficiales que genera wrangler types y su lógica pasa tests con un doble de env.AI (un objeto falso que imita la forma de las respuestas). Las respuestas de los modelos que verás son de ese doble, no de un modelo. Precios y límites comprobados en la documentación oficial ese mismo día.

Cómo funciona

Esquema de Workers AI: tu código llama a env.AI.run con un modelo, una entrada y opciones, o usa la API REST; opcionalmente la petición pasa por AI Gateway; Cloudflare la ejecuta en sus GPUs con un modelo del catálogo de texto, embeddings, imagen o voz; la respuesta vuelve completa en JSON o en streaming
Un binding, un nombre de modelo y una entrada. Cloudflare elige la GPU. Diagrama: devutilites.
  1. Añades el binding ai a tu configuración. En el Worker aparece env.AI.
  2. Llamas a env.AI.run(modelo, entrada, opciones). El modelo se identifica con un nombre del tipo @cf/<autor>/<modelo>, por ejemplo @cf/meta/llama-3.3-70b-instruct-fp8-fast. La entrada depende del tipo de modelo: messages o prompt para generar texto, text para embeddings, una imagen para clasificación…
  3. Cloudflare ejecuta el modelo en una GPU de su red y te devuelve el resultado: un objeto JSON o, con stream: true, un flujo de eventos SSE que puedes reenviar tal cual al navegador.

También se puede llamar sin Worker, por la API REST de Cloudflare (/accounts/<cuenta>/ai/run/... o el endpoint compatible con OpenAI /ai/v1/chat/completions), con un token de API que tenga permiso de Workers AI.

El catálogo de Workers AI tenía 69 modelos el día que escribí esto, de estos tipos:

TipoPara quéEjemplos
Generación de textoChat, resúmenes, extracción, agentesLlama 3.x, Qwen, gpt-oss, Mistral, Kimi
EmbeddingsBúsqueda semántica y RAGbge-m3 (multilingüe), bge-base-en-v1.5, qwen3-embedding-0.6b
Texto a imagenGenerar imágenesFLUX, Stable Diffusion
VozTranscribir (ASR) y sintetizar (TTS)Whisper, Deepgram
Clasificación, detección, traducciónModeración, etiquetas, idiomasLlama Guard, m2m100

Algunos modelos de texto admiten llamadas a funciones (function calling), LoRA (adaptadores ajustados por ti) o la API de lotes, que encola muchas peticiones y te devuelve un request_id para recoger los resultados después, sin errores por límite de velocidad. Cada ficha del catálogo indica qué admite el modelo, su ventana de contexto y su precio.

💡
Un mismo modelo puede tener varias versiones. llama-3.1-8b-instruct, -awq, -fp8 y -fp8-fast son variantes cuantizadas u optimizadas del mismo modelo, con precios distintos. Mira la ficha de cada una antes de elegir, porque algunas aparecen en la tabla de precios y su página ya no existe.

Precios: neuronas

Workers AI se factura en neuronas, una unidad que mide el cómputo en GPU. Cada modelo tiene un precio en neuronas por millón de tokens (o por imagen, por minuto de audio…), y la documentación muestra también su equivalencia en dólares.

PlanGratisDespués
Workers Free10.000 neuronas al díaNada: hay que pasar a Paid
Workers Paid10.000 neuronas al día0,011 $ por cada 1.000 neuronas

El contador se pone a cero cada día a las 00:00 UTC (las 02:00 en la España peninsular en verano). Algunos modelos grandes exigen un método de pago aunque estés dentro de la cuota.

Para hacerse una idea, con los precios de la documentación y una pregunta típica de un RAG (1.500 tokens de entrada, con el contexto, y 300 de salida):

ModeloNeuronas por millón (entrada / salida)Neuronas por preguntaPreguntas gratis al día
@cf/meta/llama-3.2-3b-instruct4.625 / 30.475≈ 16≈ 625
@cf/meta/llama-3.3-70b-instruct-fp8-fast26.668 / 204.805≈ 101≈ 99
@cf/baai/bge-m3 (embeddings)1.075≈ 1,6 por 1.500 tokens—

Pasada la cuota, la pregunta al modelo de 70B sale por unos 0,0011 $ y la del de 3B, por unos 0,00018 $. Indexar un millón de tokens de texto con bge-m3 cuesta 1.075 neuronas, ni 2 céntimos. Los tokens de salida son lo caro: limita max_tokens.

Límites

Los límites de velocidad son por tipo de tarea (y algunos por modelo), por cuenta:

TipoPeticiones por minuto
Generación de texto300 (los modelos que exigen Paid: 20, o 50 con créditos de AI Gateway)
Embeddings3.000 (bge-large-en-v1.5: 1.500)
Clasificación de texto2.000
Resumen1.500
Texto a imagen, voz a texto, imagen a texto, traducción720
Clasificación de imágenes, detección de objetos3.000
⚠️
Las inferencias en local cuentan. La documentación lo dice claro: las llamadas desde wrangler dev van a tu cuenta, gastan neuronas y cuentan para los límites. No dejes un bucle de pruebas lanzando peticiones.

El código

La configuración solo necesita el binding:

{
  "ai": { "binding": "AI" }
}

Y un Worker de chat que responde de una vez o en streaming. Uso un modelo pequeño, porque para respuestas cortas sobra, y le pongo una etiqueta (tags) para agrupar las peticiones en el panel:

// Worker mínimo de chat con Workers AI: respuesta en streaming (SSE) o de una vez
export interface EntornoChat {
  AI: Ai;
}

const MODELO = "@cf/meta/llama-3.2-3b-instruct"; // pequeño y barato: ~16 neuronas por pregunta típica

export default {
  async fetch(request, env): Promise<Response> {
    if (request.method !== "POST") return new Response("POST { pregunta, stream? }\n", { status: 405 });
    const { pregunta, stream = false } = (await request.json()) as { pregunta?: string; stream?: boolean };
    if (!pregunta) return Response.json({ error: "falta pregunta" }, { status: 400 });

    const messages = [
      { role: "system", content: "Responde en español de España, en tres frases como máximo." },
      { role: "user", content: pregunta },
    ];

    try {
      if (stream) {
        // con stream: true, run() devuelve un ReadableStream de eventos SSE
        const flujo = await env.AI.run(MODELO, { messages, stream: true, max_tokens: 256 }, { tags: ["chat"] });
        return new Response(flujo as ReadableStream, { headers: { "content-type": "text/event-stream" } });
      }
      const salida = await env.AI.run(MODELO, { messages, max_tokens: 256 }, { tags: ["chat"] });
      const texto = typeof salida === "string" ? salida : "response" in salida ? salida.response : null;
      return Response.json({ respuesta: texto, uso: typeof salida === "object" && "usage" in salida ? salida.usage : undefined });
    } catch (e) {
      // límite de neuronas agotado, rate limit, modelo inexistente…: no devuelvas el error crudo
      console.error("Workers AI:", e);
      return Response.json({ error: "el modelo no está disponible ahora" }, { status: 503 });
    }
  },
} satisfies ExportedHandler<EntornoChat>;

Tres detalles que salen de los tipos oficiales, no de la intuición:

  • La salida de run() es una unión. Para este modelo, wrangler types la declara como objeto con response, como string o como respuesta de lote asíncrono. Si accedes a salida.response sin comprobarlo, TypeScript no compila.
  • Con stream: true recibes un ReadableStream de eventos SSE. Lo devuelves con content-type: text/event-stream y el navegador lo lee con EventSource o fetch.
  • Captura los errores. Si se acaba la cuota diaria, se supera el límite de velocidad o el modelo no existe, run() lanza una excepción. No devuelvas el mensaje tal cual al cliente.

Los tests

Como no hay simulación local, la lógica se prueba con un doble: un objeto con un método run que devuelve lo que devolvería el modelo. No dice nada de la calidad de las respuestas, pero comprueba que el Worker construye bien la petición, reenvía el stream y no filtra errores:

 ✓ test/chat.test.ts > chat > sin stream devuelve JSON con la respuesta y el uso
 ✓ test/chat.test.ts > chat > con stream reenvía el ReadableStream como text/event-stream
 ✓ test/chat.test.ts > chat > si el modelo falla responde 503 sin filtrar el error

Para probarlo de verdad: npx wrangler login, npx wrangler dev y un curl -X POST localhost:8787 -d '{"pregunta":"¿Qué es un Worker?"}'. Ese paso sí gasta neuronas.

Errores comunes (y cómo evitarlos)

  • No limitar max_tokens. La salida es lo más caro y lo más lento. Ponle un tope.
  • Elegir el modelo más grande por defecto. Un 3B o un 8B resuelve muchas tareas (clasificar, extraer, resumir textos cortos) por una fracción del precio. Sube solo si la calidad no llega.
  • Usar un modelo de embeddings en inglés para textos en español. bge-base-en-v1.5 está pensado para inglés; para español, bge-m3 u otro multilingüe.
  • Probar en local como si fuera gratis. Las llamadas en wrangler dev cuentan.
  • Suponer la forma de la respuesta. Cada modelo tiene su esquema de entrada y salida, documentado en su ficha. Genera los tipos con wrangler types y deja que el compilador te avise.
  • Lanzar miles de peticiones en paralelo. Para trabajos por lotes (indexar un archivo entero, resumir miles de textos), usa la API de lotes o una cola.
  • No tener visibilidad. Sin logs no sabes qué preguntas se hacen ni cuánto cuestan. Pasa las peticiones por AI Gateway.

Cuándo usar Workers AI (y cuándo no)

Úsalo para añadir IA a una aplicación que ya vive en Cloudflare sin gestionar GPUs ni otra cuenta: chat y asistentes, resúmenes, clasificación y moderación, embeddings para búsqueda semántica con Vectorize, transcripción de audio o generación de imágenes. La cuota diaria gratuita da para prototipos y proyectos pequeños.

No es la mejor opción si necesitas el modelo más potente del mercado para una tarea difícil (los modelos cerrados de OpenAI, Anthropic o Google siguen por delante en muchas; puedes llamarlos igualmente a través de AI Gateway), si necesitas un modelo propio entero (no solo un LoRA) o si tienes GPUs propias infrautilizadas.

Sigue leyendo