Inference AI přesunuta na okraj

Až do roku 2023 bylo provozování velkého jazykového modelu téměř povinné komunikovat s externím API (OpenAI, Anthropic, Google) nebo nasazovat drahé GPU na vyhrazené infrastruktuře. Latence sítě k těmto centralizovaným koncovým bodům ke každému požadavku přidal 200–800 ms a náklady na GPU byly příliš vysoké nízkoobjemové aplikace.

Dělníci AI změnil tento scénář. Cloudflare se rozšířil AI inferenční hardware (specializované GPU) v desítkách datových center po celém světě. Modely běží na stejném hardwaru, na kterém běží váš Worker, což eliminuje zpáteční síť k externím poskytovatelům. Výsledkem je odvození latence snížené, účtované za spotřebu bez správy infrastruktury.

Co se naučíte

  • Šablony dostupné v Workers AI: LLM, vize, řeč, vkládání
  • Generování textu pomocí Llama 3.1 a streamování odpovědí
  • Modely vidění: analýza obrazu pomocí LLaVA
  • Převod řeči na text pomocí funkce Whisper
  • Vložení textu pro sémantické vyhledávání
  • AI Gateway: ukládání do mezipaměti, omezení rychlosti a pozorovatelnost požadavků AI
  • Limity, náklady a optimalizační strategie

Přehled dostupných modelů

Workers AI nabízí výběr open-source modelů optimalizovaných pro odvození na hardwaru Cloudflare. Modely jsou označeny předponou @cf/ o @hf/ (Hostováno objímání obličeje):

Kategorie Hlavní modely Případ použití
Generování textu @cf/meta/llama-3.1-8b-instruct, @cf/mistral/mistral-7b-instruct-v0.2 Chatbot, shrnutí, otázky a odpovědi, generování kódu
Generování textu (velké) @cf/meta/llama-3.3-70b-instruct-fp8-fast Komplexní uvažování, pokročilá analýza
Vidění @cf/llava-hf/llava-1.5-7b-hf, @cf/unum/uform-gen2-qwen-500m Popisky obrázků, vizuální otázky a odpovědi
Převod řeči na text @cf/openai/whisper, @cf/openai/whisper-large-v3-turbo Zvukový přepis
Vložení textu @cf/baai/bge-base-en-v1.5, @cf/baai/bge-large-en-v1.5 Sémantické vyhledávání, podobnost, RAG
Klasifikace obrázků @cf/microsoft/resnet-50 Klasifikace obrázků
Překlad @cf/meta/m2m100-1,2b Překlad více než 100 jazyků
Generování obrazu @cf/stabilityai/stable-diffusion-xl-base-1.0 Převod textu na obrázek

Konfigurace: AI Binding v wrangler.toml

Chcete-li použít Workers AI, stačí přidat vazbu [ai] v konfiguraci:

# wrangler.toml
name = "ai-worker"
main = "src/worker.ts"
compatibility_date = "2024-09-23"

# Binding per Workers AI
[ai]
binding = "AI"

Typ TypeScript vazby musí být deklarován v rozhraní Env:

// types.ts - dichiarazione del binding AI
interface Env {
  AI: Ai; // Tipo fornito da @cloudflare/workers-types
}

Generování textu s lamou 3.1

Nejčastějším případem použití je generování textu pomocí šablony instrukce-odpověď. Podívejme se, jak implementovat koncový bod chatu:

// src/worker.ts - endpoint di chat con Llama 3.1

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    if (request.method !== 'POST' || new URL(request.url).pathname !== '/chat') {
      return new Response('POST /chat required', { status: 400 });
    }

    const { messages, stream = false } = await request.json<ChatRequest>();

    // Valida l'input
    if (!Array.isArray(messages) || messages.length === 0) {
      return Response.json({ error: 'messages array required' }, { status: 400 });
    }

    if (stream) {
      // Streaming response: il modello restituisce token man mano
      const aiStream = await env.AI.run('@cf/meta/llama-3.1-8b-instruct', {
        messages,
        stream: true,
        max_tokens: 1024,
        temperature: 0.7,
      });

      // Trasforma lo stream AI in Server-Sent Events
      return new Response(aiStream, {
        headers: {
          'Content-Type': 'text/event-stream',
          'Cache-Control': 'no-cache',
          'Connection': 'keep-alive',
        },
      });
    }

    // Risposta sincrona: attende il completion completo
    const result = await env.AI.run('@cf/meta/llama-3.1-8b-instruct', {
      messages,
      max_tokens: 1024,
      temperature: 0.7,
    });

    return Response.json({
      response: (result as AiTextGenerationOutput).response,
      usage: {
        // Workers AI non espone ancora i token counts nella risposta base
        model: '@cf/meta/llama-3.1-8b-instruct',
      },
    });
  },
};

interface ChatRequest {
  messages: Array<{ role: 'system' | 'user' | 'assistant'; content: string }>;
  stream?: boolean;
}

interface Env {
  AI: Ai;
}

Úplnější příklad, který implementuje systémového asistenta a robustní zpracování chyb:

// src/assistant-worker.ts

const SYSTEM_PROMPT = `Sei un assistente tecnico esperto in cloud computing e edge computing.
Rispondi in modo conciso e tecnico. Se non conosci la risposta, dillo chiaramente.
Non inventare informazioni. Rispondi sempre in italiano a meno che l'utente non scriva in un'altra lingua.`;

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    if (request.method !== 'POST') {
      return new Response('Method Not Allowed', { status: 405 });
    }

    let body: AssistantRequest;
    try {
      body = await request.json<AssistantRequest>();
    } catch {
      return Response.json({ error: 'Invalid JSON body' }, { status: 400 });
    }

    if (!body.question?.trim()) {
      return Response.json({ error: 'question field is required' }, { status: 400 });
    }

    try {
      const result = await env.AI.run('@cf/meta/llama-3.1-8b-instruct', {
        messages: [
          { role: 'system', content: SYSTEM_PROMPT },
          { role: 'user', content: body.question },
        ],
        max_tokens: 2048,
        temperature: 0.3, // Bassa temperatura per risposte piu deterministiche
      }) as AiTextGenerationOutput;

      return Response.json({
        answer: result.response,
        model: '@cf/meta/llama-3.1-8b-instruct',
        timestamp: new Date().toISOString(),
      });
    } catch (err) {
      console.error('AI inference error:', err);
      return Response.json(
        { error: 'AI inference failed', details: (err as Error).message },
        { status: 500 }
      );
    }
  },
};

interface AssistantRequest {
  question: string;
}

interface Env {
  AI: Ai;
}

Modely vidění: Analýza obrazu

Modely vidění umožňují analyzovat vstupní obrázky spolu s otázkou textové. To je užitečné pro moderování obsahu, extrakci informací z naskenovaných dokumentů a funkcí usnadnění:

// src/vision-worker.ts - analisi immagini con LLaVA

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    if (request.method !== 'POST') {
      return new Response('Method Not Allowed', { status: 405 });
    }

    // Accetta immagine come Base64 o URL
    const body = await request.json<VisionRequest>();

    let imageData: number[];

    if (body.imageUrl) {
      // Scarica l'immagine e converti in array di byte
      const imgResponse = await fetch(body.imageUrl);
      if (!imgResponse.ok) {
        return Response.json({ error: 'Failed to fetch image' }, { status: 400 });
      }
      const buffer = await imgResponse.arrayBuffer();
      imageData = Array.from(new Uint8Array(buffer));
    } else if (body.imageBase64) {
      // Decodifica Base64
      const binaryString = atob(body.imageBase64);
      imageData = Array.from({ length: binaryString.length }, (_, i) =>
        binaryString.charCodeAt(i)
      );
    } else {
      return Response.json({ error: 'imageUrl or imageBase64 required' }, { status: 400 });
    }

    const prompt = body.prompt ?? 'Descrivi questa immagine in dettaglio in italiano.';

    const result = await env.AI.run('@cf/llava-hf/llava-1.5-7b-hf', {
      image: imageData,
      prompt,
      max_tokens: 512,
    }) as AiTextGenerationOutput;

    return Response.json({
      description: result.response,
      prompt,
      model: '@cf/llava-hf/llava-1.5-7b-hf',
    });
  },
};

interface VisionRequest {
  imageUrl?: string;
  imageBase64?: string;
  prompt?: string;
}

interface Env {
  AI: Ai;
}

Převod řeči na text s šepotem

Workers AI obsahuje Whisper pro přepis zvuku. Model přijímá zvuk ve formátu ArrayBuffer a vrátí přepis s časovým razítkem volitelné:

// src/transcribe-worker.ts - Speech-to-text con Whisper

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    if (request.method !== 'POST') {
      return new Response('Method Not Allowed', { status: 405 });
    }

    const contentType = request.headers.get('Content-Type') ?? '';

    // Accetta audio come multipart/form-data o application/octet-stream
    let audioBuffer: ArrayBuffer;

    if (contentType.includes('multipart/form-data')) {
      const formData = await request.formData();
      const audioFile = formData.get('audio') as File | null;
      if (!audioFile) {
        return Response.json({ error: 'audio field required in form data' }, { status: 400 });
      }
      audioBuffer = await audioFile.arrayBuffer();
    } else {
      // Raw binary audio
      audioBuffer = await request.arrayBuffer();
    }

    if (audioBuffer.byteLength === 0) {
      return Response.json({ error: 'Empty audio data' }, { status: 400 });
    }

    // Limita a 25MB (limite Whisper)
    if (audioBuffer.byteLength > 25 * 1024 * 1024) {
      return Response.json({ error: 'Audio file too large (max 25MB)' }, { status: 413 });
    }

    const result = await env.AI.run('@cf/openai/whisper', {
      audio: Array.from(new Uint8Array(audioBuffer)),
    }) as AiSpeechRecognitionOutput;

    return Response.json({
      text: result.text,
      wordCount: result.text.split(/\s+/).filter(Boolean).length,
      model: '@cf/openai/whisper',
    });
  },
};

interface Env {
  AI: Ai;
}

Vložení textu pro sémantické vyhledávání

Vložení jsou číselné vektory, které představují sémantický význam textu. Workers AI obsahuje modely BGE optimalizované pro sémantické vyhledávání. V kombinaci s Vectorize (vektorová databáze Cloudflare) vám umožňují stavět RAG potrubí zcela na okraji:

// src/embedding-worker.ts - generazione embeddings + ricerca semantica

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);

    if (url.pathname === '/embed' && request.method === 'POST') {
      const { texts } = await request.json<EmbedRequest>();

      if (!Array.isArray(texts) || texts.length === 0) {
        return Response.json({ error: 'texts array required' }, { status: 400 });
      }

      // BGE genera embedding di 768 dimensioni (base) o 1024 (large)
      const result = await env.AI.run('@cf/baai/bge-base-en-v1.5', {
        text: texts,
      }) as AiTextEmbeddingsOutput;

      return Response.json({
        embeddings: result.data,
        dimensions: result.data[0]?.length ?? 0,
        count: result.data.length,
        model: '@cf/baai/bge-base-en-v1.5',
      });
    }

    if (url.pathname === '/search' && request.method === 'POST') {
      const { query, topK = 5 } = await request.json<SearchRequest>();

      // 1. Genera l'embedding per la query
      const queryEmbed = await env.AI.run('@cf/baai/bge-base-en-v1.5', {
        text: [query],
      }) as AiTextEmbeddingsOutput;

      // 2. Ricerca semantica su Vectorize
      const results = await env.VECTORIZE.query(queryEmbed.data[0], {
        topK,
        returnMetadata: 'all',
      });

      return Response.json({
        query,
        results: results.matches.map((match) => ({
          id: match.id,
          score: match.score,
          metadata: match.metadata,
        })),
      });
    }

    return new Response('Not Found', { status: 404 });
  },
};

interface EmbedRequest {
  texts: string[];
}

interface SearchRequest {
  query: string;
  topK?: number;
}

interface Env {
  AI: Ai;
  VECTORIZE: VectorizeIndex;
}

AI Gateway: Pozorovatelnost a ukládání do mezipaměti

Brána umělé inteligence Cloudflare je to transparentní proxy, že ano pozice před voláními AI (jak Workers AI, tak externí poskytovatelé, jako je OpenAI). Přidává sémantické ukládání do mezipaměti, omezení rychlosti, protokolování a automatický přechod:

// src/worker-with-gateway.ts - Workers AI via AI Gateway

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const { prompt } = await request.json<{ prompt: string }>();

    // Usa il gateway invece del binding diretto
    // Il gateway aggiunge: caching, retry, logging, rate limiting
    const response = await fetch(
      `https://gateway.ai.cloudflare.com/v1/${env.CF_ACCOUNT_ID}/${env.AI_GATEWAY_ID}/workers-ai/@cf/meta/llama-3.1-8b-instruct`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${env.CF_API_TOKEN}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          messages: [{ role: 'user', content: prompt }],
          max_tokens: 512,
        }),
      }
    );

    if (!response.ok) {
      const error = await response.text();
      return Response.json({ error }, { status: response.status });
    }

    const result = await response.json();
    return Response.json(result);
  },
};

interface Env {
  AI: Ai;
  CF_ACCOUNT_ID: string;
  CF_API_TOKEN: string;
  AI_GATEWAY_ID: string;
}

Případně můžete bránu nakonfigurovat přímo ve vazbě AI na wrangler.toml:

# wrangler.toml con AI Gateway
[ai]
binding = "AI"
# Il gateway viene usato automaticamente per tutte le chiamate
# Configurato nella dashboard Cloudflare

Omezení a úvahy o nákladech

Model Zdarma (neuronové jednotky) Placené ($ za 1 000 neuronů) Typická latence
Lama 3.1 8B 10 000 NU/den zdarma 0,011 $ / 1 000 NU ~500 ms-2s (závisí na tokenech)
Lama 3.3 70B FP8 Zahrnuto v placeném plánu 0,050 $ / 1 000 NU ~1-5s
Šepot 10 000 NU/den zdarma 0,011 $ / 1 000 NU ~1-3s za minutu zvuku
vložení BGE 10 000 NU/den zdarma 0,011 $ / 1 000 NU ~50-200 ms
Stabilní difúze XL 10 000 NU/den zdarma 0,020 $ / obrázek ~3-10s

Časové limity a limity CPU

Workers AI funguje mimo běžný rozpočet CPU pracovníka (placený plán 30 s). U velkých modelů, jako je Llama 70B, to však může trvat 5–15 sekund reagovat. V těchto případech nezapomeňte použít streamování vracet tokeny za pochodu a nepřekračovat časový limit HTTP klienta. Pro dlouhé závěry zvažte použití fronty (Workers Queues) a upozorněte klienta po dokončení.

Výrobní vzor: RAG at the Edge

Stále častějším vzorem je RAG (generace rozšířeného vyhledávání) zcela na okraji: Vektorizace pro získávání, Workers AI pro vkládání a generování.

// src/rag-worker.ts - RAG completo all'edge

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    if (request.method !== 'POST') return new Response('POST only', { status: 405 });

    const { question } = await request.json<{ question: string }>();

    // Step 1: Genera l'embedding della domanda
    const queryEmbedding = await env.AI.run('@cf/baai/bge-base-en-v1.5', {
      text: [question],
    }) as AiTextEmbeddingsOutput;

    // Step 2: Recupera i chunk rilevanti dal vector store
    const relevant = await env.DOCS.query(queryEmbedding.data[0], {
      topK: 3,
      returnMetadata: 'all',
    });

    // Step 3: Costruisce il contesto dai chunk recuperati
    const context = relevant.matches
      .map((m) => m.metadata?.['text'] as string ?? '')
      .filter(Boolean)
      .join('\n\n---\n\n');

    // Step 4: Genera la risposta con il contesto
    const answer = await env.AI.run('@cf/meta/llama-3.1-8b-instruct', {
      messages: [
        {
          role: 'system',
          content: `Rispondi alla domanda basandoti SOLO sul contesto fornito.
Se il contesto non contiene informazioni sufficienti, dillo esplicitamente.
Contesto:
${context}`,
        },
        { role: 'user', content: question },
      ],
      max_tokens: 1024,
      temperature: 0.1,
    }) as AiTextGenerationOutput;

    return Response.json({
      question,
      answer: answer.response,
      sources: relevant.matches.map((m) => ({
        id: m.id,
        score: m.score,
        title: m.metadata?.['title'],
      })),
    });
  },
};

interface Env {
  AI: Ai;
  DOCS: VectorizeIndex;
}

Závěry a další kroky

Umělá inteligence pracovníků představuje změnu paradigmatu v přístupu k vyvozování AI: žádná GPU ke správě, žádní externí poskytovatelé k integraci, fakturace pro spotřebu s velkorysou bezplatnou úrovní. Odráží 4000% meziroční růst do 1. čtvrtletí 2026 rychlé přijetí vývojáři, kteří hledají jednodušší cestu vůči AI ve svých produktech.

Kombinace Workers AI + Vectorize + Durable Objects (pro správu historie konverzací) vám umožňuje vytvořit kompletní asistenty AI na platformě Cloudflare, bez externích závislostí.

Další články v seriálu

  • Článek 6: Vercel Edge Runtime — pokročilý middleware, Geolokace a A/B testování: Jak Vercel používá edge runtime s Next.js pro přizpůsobení a příznaky funkcí.
  • Článek 7: Geografické směrování na okraji — Personalizace Obsah a soulad s GDPR: Vytvářejte geografickou logiku, aniž byste se dotkli hlavního serveru.
  • Článek 8: Cache API a strategie zneplatnění v Cloudflare Pracovníci: Programovatelné CDN s TTL, zatuchlý-běh-obnovení platnosti a čištění podle klíče.