Pourquoi les Edge Functions pour l'IA
Trois raisons pour lesquelles les Edge Functions sont le bon choix pour les appels API IA :
1. Sécurité : Votre clé API OpenAI/Anthropic vit comme un secret côté serveur, jamais exposé au client. Quiconque accède à votre code frontend ne peut pas extraire la clé. C'est une exigence absolue, une clé OpenAI exposée peut générer des factures de plusieurs milliers d'euros en quelques heures.
2. Accès à la base de données : Les Edge Functions s'exécutent dans l'infrastructure de Supabase et ont un accès direct et faible latence à votre base de données PostgreSQL. Vous pouvez récupérer le contexte utilisateur, stocker les résultats et logger l'utilisation dans la même fonction qui appelle l'IA.
3. Support du streaming : Les Edge Functions supportent le streaming de réponses (Response streaming), ce qui vous permet d'envoyer la sortie IA au client mot par mot, améliorant considérablement la performance perçue pour les longues réponses IA.
Fonction proxy OpenAI basique
La plus simple des Edge Functions : recevoir un prompt, appeler OpenAI, retourner la réponse.
La fonction importe le client OpenAI via npm, lit la clé API depuis les variables d'environnement Deno, reçoit le prompt en JSON, appelle chat.completions.create avec le modèle gpt-4o et un max_tokens de 500, puis retourne le résultat en JSON.
Déployez avec supabase functions deploy openai-proxy. Définissez les secrets avec supabase secrets set OPENAI_API_KEY=sk-....
Pour les apps multilingues destinées au marché français, ajoutez un paramètre language à votre fonction et injectez la langue dans le system prompt. Vous pouvez également détecter automatiquement la langue de l'input utilisateur avec un appel préliminaire à GPT-4o mini (très peu coûteux) et adapter la réponse en conséquence.
Ajout de l'authentification et de la limitation de débit
Chaque Edge Function IA devrait vérifier que l'utilisateur est authentifié et contrôler ses limites d'utilisation.
Le pattern standard :
1. Extraire le token JWT du header Authorization
2. Créer un client Supabase avec la service role key
3. Appeler auth.getUser(token) pour valider l'authentification
4. Requêter la table ai_usage_log pour compter les appels des dernière heure
5. Retourner une erreur 429 si la limite est atteinte
6. Sinon, procéder à l'appel OpenAI et logger la nouvelle utilisation
Adaptez les limites selon votre modèle de tarification : plan gratuit = 10 requêtes/heure, plan pro = 100 requêtes/heure, plan enterprise = illimité. Cette granularité permet de construire un modèle de monétisation des fonctionnalités IA directement dans votre backend.
Streaming des réponses vers WeWeb
Le streaming envoie progressivement la sortie IA au client, les utilisateurs voient le texte apparaître mot par mot au lieu d'attendre la réponse complète.
Dans l'Edge Function, créez la complétion avec stream: true, puis wrappez le flux async dans un ReadableStream qui encode chaque chunk de texte et le transmet au client via une réponse de type text/event-stream.
Dans WeWeb, utilisez une action JavaScript personnalisée pour fetch l'URL du stream et mettre à jour une variable de page caractère par caractère au fur et à mesure de l'arrivée des chunks.
Le streaming améliore considérablement la perception de performance pour les générations de texte longues (rapports, analyses, articles). Pour les fonctionnalités où la réponse est courte (extraction de données, classification), le non-streaming est plus simple à implémenter et les performances perçues sont équivalentes.
Construire un pipeline RAG (Retrieval Augmented Generation)
Le RAG améliore les réponses IA en injectant des connaissances pertinentes dans le prompt au moment de la requête. Architecture :
1. Ingestion des connaissances (exécuté une fois) : Pour chaque document de votre base de connaissances, appelez l'API d'embeddings d'OpenAI pour obtenir un vecteur de 1536 dimensions. Stockez les vecteurs dans Supabase en utilisant l'extension pgvector.
2. Au moment de la requête : Quand un utilisateur pose une question, calculez l'embedding de la question (même API d'embedding), puis lancez une recherche par similarité dans Supabase : sélectionnez les documents les plus proches sémantiquement en utilisant l'opérateur de distance cosinus <=>, limitez aux 3 meilleurs résultats.
3. Prompt augmenté : Injectez les 3 documents correspondants dans le system prompt : "Réponds en utilisant uniquement le contexte suivant : [docs]. Si la réponse n'est pas dans le contexte, dis que tu ne sais pas."
Résultat : l'IA répond uniquement à partir de votre documentation, sans hallucination. Particulièrement utile pour les chatbots support en français où la précision terminologique est importante.
Optimisation des cold starts pour les Edge Functions
Les Supabase Edge Functions reposent sur Deno et tournent sur le réseau edge global de Deno Deploy. Un cold start, la première invocation d'une fonction qui n'a pas été appelée récemment, prend typiquement 200 à 500 ms. Pour les fonctionnalités IA où les utilisateurs attendent un retour instantané, cette latence de cold start peut être perceptible.
Plusieurs stratégies d'optimisation réduisent l'impact des cold starts. D'abord, importez uniquement ce dont vous avez besoin. Une fonction qui importe le SDK OpenAI complet ajoute plus de poids au bundle qu'une fonction qui n'importe que le type ChatCompletion. Utilisez des imports nommés et des patterns favorables au tree-shaking. Ensuite, préchauffez les fonctions critiques en les appelant selon un planning. Un cron job Supabase qui appelle votre fonction IA avec une requête synthétique toutes les 5 minutes garde l'instance chaude au coût de quelques appels API par jour.
Enfin, utilisez la mise en cache des réponses pour les prompts déterministes. Si les utilisateurs posent fréquemment le même type de question (résumé de document, classification de catégorie), mettez en cache la sortie dans une table Supabase indexée sur un hash de l'entrée. Retournez le résultat en cache immédiatement pour les entrées répétées, zéro cold start, zéro coût API, réponse en moins de 10 ms. C'est particulièrement efficace pour les tâches de classification où l'ensemble des entrées possibles est borné.
Inférence IA en périphérie : appeler OpenAI et Anthropic depuis les Edge Functions
Le SDK OpenAI et le SDK Anthropic fonctionnent tous les deux dans l'environnement d'exécution Deno, celui qu'utilisent les Supabase Edge Functions. Vous les importez via des spécificateurs npm: : import OpenAI from 'npm:openai' et import Anthropic from 'npm:@anthropic-ai/sdk'. Les deux SDK gèrent les appels HTTPS, la logique de retry et la gestion d'erreurs pour leurs API respectives.
Pour une fonctionnalité IA en production, vous devriez gérer la sélection du modèle de façon dynamique. Stockez le nom du modèle comme secret de Supabase Edge Function plutôt que de le coder en dur. Cela vous permet de passer de gpt-4o à gpt-4o-mini (pour les tâches à moindre coût) ou de claude-3-5-sonnet à claude-3-haiku sans redéployer la fonction. Vous mettez à jour le secret et la prochaine requête utilise le nouveau modèle.
La gestion des coûts est critique pour les fonctions IA avec un accès utilisateur ouvert. Journalisez chaque appel API avec le nombre de tokens retourné dans la réponse. Configurez des alertes de dépenses mensuelles dans votre dashboard OpenAI ou Anthropic. Pour les utilisateurs du plan gratuit, plafonnez l'usage à un budget de tokens par mois et appliquez-le dans l'Edge Function avant que l'appel API ne soit fait. Nous intégrons cette couche de suivi des coûts dans chaque fonctionnalité IA que nous livrons, elle a évité des factures mensuelles inattendues de 3 000 $ sur plus d'un projet client.
Réponses en streaming : le pattern Server-Sent Events
Le pattern Server-Sent Events (SSE) est la méthode standard pour streamer des réponses IA depuis une Supabase Edge Function vers un navigateur. La fonction définit Content-Type: text/event-stream et écrit les chunks au format data: {text}\n\n au fur et à mesure qu'ils arrivent depuis l'API IA. Le navigateur utilise l'API native EventSource ou un fetch avec ReadableStream pour consommer le flux de façon incrémentale.
Dans WeWeb, implémenter le SSE nécessite une action JavaScript personnalisée car les actions de requête HTTP intégrées attendent la réponse complète avant de continuer. L'action ouvre une requête fetch, lit le corps de la réponse comme un flux via response.body.getReader(), décode chaque chunk, et l'ajoute à une variable de page. Cette variable de page est liée à un élément texte sur le canvas, donc les utilisateurs voient le texte apparaître caractère par caractère.
Le résultat est une UX de fonctionnalité IA nettement meilleure. Une réponse IA de 300 mots de GPT-4o prend environ 5 secondes à se terminer. Sans streaming, l'utilisateur voit un spinner pendant 5 secondes puis le texte complet apparaît. Avec le streaming, il commence à lire la réponse dans les 300 ms suivant la soumission de son prompt. Dans les tests utilisateurs, le streaming est systématiquement perçu comme plus réactif et plus intelligent, même si le temps de génération total est identique.
Utiliser les Edge Functions comme gestionnaires de webhooks
Les Edge Functions sont un excellent choix pour gérer les webhooks de services externes, événements de paiement Stripe, notifications push GitHub, SMS Twilio, ou tout service qui envoie du POST vers une URL. Elles sont toujours disponibles (pas besoin de démarrer un serveur), distribuées globalement (faible latence depuis le datacenter de l'expéditeur du webhook), et ont un accès direct à la base de données Supabase pour mettre à jour les enregistrements en réponse aux événements.
Une Edge Function de webhook Stripe valide la signature du webhook, analyse le type d'événement, et met à jour l'enregistrement Supabase concerné. Pour un événement de mise à niveau d'abonnement : vérifiez la signature avec stripe.webhooks.constructEvent() et votre secret de webhook, extrayez l'ID client et le nouveau plan, mettez à jour la table subscriptions dans Supabase, et retournez une réponse 200 dans les 5 secondes (le timeout de Stripe). C'est le gestionnaire complet du cycle de vie du paiement, sans serveur séparé nécessaire.
Pour les applications IA, les webhooks sont utilisés pour le traitement asynchrone. Quand un utilisateur upload un document pour une analyse IA, vous ne le faites pas attendre : vous mettez la tâche en file via une insertion de ligne Supabase, un job en arrière-plan la récupère et appelle l'API IA, et quand le résultat est prêt, un trigger Supabase envoie une notification push ou met à jour le dashboard via le temps réel. Les Edge Functions gèrent à la fois le webhook d'entrée et la notification sortante.
Patterns de sécurité pour les Edge Functions IA
La mesure de sécurité la plus importante pour toute Edge Function IA est de vérifier l'identité de l'appelant avant de faire un quelconque appel API. Extrayez toujours le JWT du header Authorization: Bearer, appelez supabase.auth.getUser(token) pour le vérifier, et contrôlez que l'utilisateur a le rôle ou le niveau d'abonnement approprié pour l'opération demandée. Une fonction IA non authentifiée est un accès direct à une dépense API illimitée pour quiconque découvre l'URL de votre endpoint.
La gestion des secrets dans les Supabase Edge Functions utilise la commande CLI supabase secrets set et Deno.env.get() à l'exécution. Ne codez jamais en dur des clés API dans le code source d'une fonction, même dans un dépôt privé, les secrets appartiennent au coffre de secrets, pas au contrôle de version. Faites tourner les secrets immédiatement si un dépôt est accidentellement rendu public ou si une clé est journalisée par erreur dans des traces d'erreur.
La validation des entrées empêche les attaques par injection de prompt, où un utilisateur malveillant construit une entrée qui change le comportement de l'IA. Validez la longueur de l'entrée, retirez les caractères dangereux, et si la fonction utilise un system prompt qui inclut des données fournies par l'utilisateur, assainissez l'entrée utilisateur avant l'interpolation. Une simple vérification de longueur (if (prompt.length > 2000) return error) élimine toute une catégorie d'abus où des utilisateurs construisent des prompts extrêmement longs pour maximiser le coût de calcul.