Skip to content
Learni
View all tutorials
Intelligence Artificielle

Comment intégrer Fireworks.ai dans Next.js en 2026

Introduction

Fireworks.ai est une plateforme d'inférence IA ultra-rapide qui héberge des modèles open-source comme Llama 3.1, Mistral ou Qwen, optimisés pour des latences inférieures à 100ms. Contrairement à OpenAI, elle excelle en coût-efficacité et vitesse pour les apps en temps réel, idéale pour les chatbots, agents IA ou RAG.

Ce tutoriel advanced vous guide pour intégrer Fireworks.ai dans une app Next.js 15 (App Router). Nous construirons un chatbot avec streaming SSE, appels de functions/tools, gestion d'erreurs robuste et UI réactive. Pourquoi 2026 ? Les APIs ont évolué avec un support natif des modèles multimodaux et fine-tuning serverless.

À la fin, vous aurez un prototype production-ready, scalable sur Vercel. Gain concret : 5x plus rapide que Grok ou GPT-4o-mini, à 10% du coût. Prêt à booster vos apps IA ? (128 mots)

Prérequis

  • Compte gratuit sur fireworks.ai avec clé API (crédits offerts au signup)
  • Node.js 20+ et npm/yarn/pnpm
  • Next.js 15+ (App Router)
  • Connaissances avancées en TypeScript, React Server Components et ReadableStreams
  • Éditeur comme VS Code avec extension TypeScript
  • Outils de test : curl ou Postman

Initialiser le projet Next.js

terminal
npx create-next-app@latest fireworks-chatbot --typescript --tailwind --eslint --app --src-dir --import-alias "@/*"
cd fireworks-chatbot
npm install
npm install @types/node

Cette commande crée un projet Next.js 15 optimisé pour TypeScript et Tailwind. L'option --app active l'App Router pour les Server Actions et streaming natif. Évitez les templates par défaut pour un contrôle total des dépendances.

Obtenir et configurer la clé API

  1. Inscrivez-vous sur app.fireworks.ai.
  2. Allez dans Account Settings > API Keys et générez une clé (format fwk-...).
  3. Dans l'Explore Models, testez Llama-3.1-70B-Instruct pour valider (interface Playground intuitive avec streaming live).
Copiez la clé : elle expire jamais mais surveillez les quotas (1M tokens/mois gratuit). Utilisez-la en serveur uniquement pour sécurité.

Configuration de l'environnement

.env.local
FIREWORKS_API_KEY=sk-fwk-YOUR_KEY_HERE
NEXT_PUBLIC_APP_URL=http://localhost:3000
MODEL_ID=accounts/fireworks/models/llama-v3p1-70b-instruct
MAX_TOKENS=4096
TEMPERATURE=0.7

Ce fichier définit les variables d'env critiques. MODEL_ID pointe vers un modèle précis (vérifiez dans l'interface Fireworks). Ajoutez .env.local à .gitignore. Utilisez process.env en runtime pour sécurité ; évitez les fuites client-side.

Route API basique pour chat

src/app/api/chat/route.ts
import { NextRequest, NextResponse } from 'next/server';

type Message = { role: 'user' | 'assistant'; content: string };

export async function POST(req: NextRequest) {
  try {
    const { messages } = await req.json() as { messages: Message[] };
    const apiKey = process.env.FIREWORKS_API_KEY!;
    const model = process.env.MODEL_ID!;

    const response = await fetch('https://api.fireworks.ai/inference/v1/chat/completions', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        model,
        messages,
        max_tokens: parseInt(process.env.MAX_TOKENS || '4096'),
        temperature: parseFloat(process.env.TEMPERATURE || '0.7'),
      }),
    });

    if (!response.ok) throw new Error(`API error: ${response.status}`);

    const data = await response.json();
    return NextResponse.json({ content: data.choices[0].message.content });
  } catch (error) {
    return NextResponse.json({ error: 'Erreur génération' }, { status: 500 });
  }
}

Cette route POST gère un chat simple avec historique messages (compatible OpenAI format). Elle utilise fetch natif pour contrôle granulaire. Testez avec curl : curl -X POST .... Piège : validez toujours messages non vide et gérez rate limits (429).

Passer au streaming SSE

Pour une UX fluide comme ChatGPT, implémentez Server-Sent Events (SSE). Fireworks supporte nativement stream: true. L'UI recevra les tokens en temps réel via EventSource ou fetch. Avantage : latence perçue <200ms.

Route API avec streaming SSE

src/app/api/chat/stream/route.ts
import { NextRequest, NextResponse } from 'next/server';

import { Readable } from 'stream';

type Message = { role: 'user' | 'assistant'; content: string };

export async function POST(req: NextRequest) {
  try {
    const { messages } = await req.json() as { messages: Message[] };
    const apiKey = process.env.FIREWORKS_API_KEY!;
    const model = process.env.MODEL_ID!;

    const response = await fetch('https://api.fireworks.ai/inference/v1/chat/completions', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        model,
        messages,
        max_tokens: parseInt(process.env.MAX_TOKENS || '4096'),
        temperature: parseFloat(process.env.TEMPERATURE || '0.7'),
        stream: true,
      }),
    });

    if (!response.ok) throw new Error(`API error: ${response.status}`);

    const stream = Readable.fromWeb(response.body!);

    return new NextResponse(stream, {
      headers: {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive',
        'Access-Control-Allow-Origin': '*',
      },
    });
  } catch (error) {
    return NextResponse.json({ error: 'Erreur stream' }, { status: 500 });
  }
}

Cette route streame les tokens via SSE. Readable.fromWeb() transforme le body en Node stream. Headers SSE essentiels pour CORS et no-cache. Piège : toujours clore le stream proprement ; testez avec curl --no-buffer. Scalable sur Vercel Edge.

Composant UI chat avec streaming

src/app/chat/page.tsx
 'use client';

import { useState, useRef, useEffect } from 'react';

export default function ChatPage() {
  const [messages, setMessages] = useState<{ role: string; content: string }[]>([]);
  const [input, setInput] = useState('');
  const [loading, setLoading] = useState(false);
  const messagesEndRef = useRef<HTMLDivElement>(null);

  const scrollToBottom = () => {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  };

  useEffect(scrollToBottom, [messages]);

  const sendMessage = async () => {
    if (!input.trim() || loading) return;

    const userMsg = { role: 'user', content: input };
    setMessages((prev) => [...prev, userMsg]);
    setLoading(true);
    setInput('');

    const res = await fetch('/api/chat/stream', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ messages: [...messages, userMsg] }),
    });

    const reader = res.body?.getReader();
    const decoder = new TextDecoder();
    let assistantMsg = { role: 'assistant', content: '' };

    while (true) {
      const { done, value } = await reader!.read();
      if (done) break;

      const chunk = decoder.decode(value);
      const lines = chunk.split('\n');
      for (const line of lines) {
        if (line.startsWith('data: ')) {
          const data = line.slice(6);
          if (data === '[DONE]') continue;
          const parsed = JSON.parse(data);
          assistantMsg.content += parsed.choices[0].delta.content || '';
          setMessages((prev) => {
            const newMsgs = [...prev];
            newMsgs[newMsgs.length - 1] = assistantMsg;
            return newMsgs;
          });
        }
      }
    }

    setMessages((prev) => [...prev, assistantMsg]);
    setLoading(false);
  };

  return (
    <div className="flex flex-col h-screen max-w-2xl mx-auto p-4">
      <div className="flex-1 overflow-y-auto space-y-4 mb-4">
        {messages.map((msg, i) => (
          <div key={i} className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`}>
            <div className={`max-w-xs p-3 rounded-lg ${msg.role === 'user' ? 'bg-blue-500 text-white' : 'bg-gray-200'}`}>
              {msg.content}
            </div>
          </div>
        ))}
        {loading && (
          <div className="flex justify-start">
            <div className="max-w-xs p-3 bg-gray-200 rounded-lg">...</div>
          </div>
        )}
        <div ref={messagesEndRef} />
      </div>
      <div className="flex space-x-2">
        <input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          className="flex-1 p-3 border rounded-lg"
          onKeyDown={(e) => e.key === 'Enter' && sendMessage()}
          placeholder="Votre message..."
        />
        <button
          onClick={sendMessage}
          disabled={loading}
          className="px-6 py-3 bg-blue-500 text-white rounded-lg disabled:opacity-50"
        >
          Envoyer
        </button>
      </div>
    </div>
  );
}

Composant client-side avec useState pour messages et streaming via ReadableStream. Parse les chunks SSE (format OpenAI). Auto-scroll fluide. Piège : gérer delta.content null et backpressure ; optimisez avec Suspense pour SSR.

Ajouter support tools/functions

src/app/api/chat/tools/route.ts
import { NextRequest, NextResponse } from 'next/server';

type Message = { role: 'user' | 'assistant' | 'tool'; content: string; tool_calls?: any[] };

export async function POST(req: NextRequest) {
  const { messages } = await req.json() as { messages: Message[] };
  const apiKey = process.env.FIREWORKS_API_KEY!;
  const model = process.env.MODEL_ID!;

  // Exemple tool: calculatrice
  const tools = [
    {
      type: 'function',
      function: {
        name: 'calculate',
        description: 'Calcule une opération mathématique',
        parameters: {
          type: 'object',
          properties: {
            expression: { type: 'string', description: 'ex: 2+2*3' },
          },
          required: ['expression'],
        },
      },
    },
  ];

  let finalMessages = [...messages];

  const response = await fetch('https://api.fireworks.ai/inference/v1/chat/completions', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model,
      messages: finalMessages,
      tools,
      tool_choice: 'auto',
      temperature: 0.1,
    }),
  });

  const data = await response.json();
  const choice = data.choices[0];

  if (choice.message.tool_calls) {
    for (const toolCall of choice.message.tool_calls) {
      const funcName = toolCall.function.name;
      const args = JSON.parse(toolCall.function.arguments);
      let toolResult = '';

      if (funcName === 'calculate') {
        try {
          toolResult = eval(args.expression).toString(); // DANGER: prod utilisez mathjs
        } catch {
          toolResult = 'Erreur calcul';
        }
      }

      finalMessages.push({
        role: 'tool',
        tool_call_id: toolCall.id,
        content: toolResult,
      });

      // Appel récursif pour réponse finale
      const finalRes = await fetch('https://api.fireworks.ai/inference/v1/chat/completions', {
        method: 'POST',
        headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
        body: JSON.stringify({ model, messages: finalMessages }),
      });

      const finalData = await finalRes.json();
      return NextResponse.json({ content: finalData.choices[0].message.content });
    }
  }

  return NextResponse.json({ content: choice.message.content });
}

Ajoute function calling pour agents intelligents (ex: calculatrice). Boucle tool calls + réponse finale. Récursif pour chaîne tools. Piège : eval() insecure (utilisez safe-eval ou math.js) ; limitez profondeur pour éviter boucles infinies.

Lancer et tester l'app

Exécutez npm run dev. Accédez à /chat. Testez streaming et tools : "Calcule 15 * 3 + 7". Logs serveur pour debug. Déployez sur Vercel : vercel --prod (env vars auto).

Bonnes pratiques

  • Choisissez le bon modèle : Llama-3.1-8B pour latence, 70B pour précision (testez via interface Fireworks).
  • Rate limiting : Implémentez Upstash Redis ou middleware Next.js (max 60 req/min).
  • Caching : Cachez prompts système avec Vercel KV ; réutilisez contextes longs.
  • Sécurité : Validez inputs Zod, secrets en env, pas de clé client-side.
  • Monitoring : Intégrez OpenTelemetry pour tracer latences (Fireworks metrics dashboard).

Erreurs courantes à éviter

  • Oubli stream: true : Réponses batchées, UX lente.
  • Pas de gestion delta null : UI freeze sur chunks vides.
  • Rate limit ignoré : 429 errors ; implémentez retry exponential backoff.
  • Modèle non-instruct : Réponses incohérentes ; forcez *-Instruct variants.

Pour aller plus loin

  • Fine-tuning serverless sur Fireworks : docs.
  • RAG avec Fireworks + Pinecone.
  • Multimodal (vision) avec Llava-1.6.
Découvrez nos formations IA avancées Learni pour maîtriser agents autonomes et déploiement prod.
Comment intégrer Fireworks.ai dans Next.js en 2026 | Learni