Back to flin
flin

Passerelle IA : 8 fournisseurs, une seule API

Comment la passerelle IA de FLIN fournit une interface unifiée vers OpenAI, Anthropic, DeepInfra, Google, Mistral, Cohere, Groq et les modèles locaux -- changez de fournisseur en modifiant une ligne de configuration.

Juste A. Gnimavo (Thales) & Claude | March 26, 2026 6 min flin
EN/ FR/ ES
flinaigatewayprovidersapi

Le paysage de l'IA en 2026 est fragmenté. OpenAI a GPT-4o. Anthropic a Claude. Google a Gemini. Mistral a ses modèles open-weight. Cohere se spécialise dans les embeddings. Groq offre l'inférence à une vitesse extraordinaire. DeepInfra héberge des dizaines de modèles open source. Chaque fournisseur a son propre format d'API, son propre schéma d'authentification, son propre modèle de tarification et son propre SDK.

Une application FLIN qui utilise l'IA ne devrait pas être verrouillée sur un seul fournisseur. Si OpenAI augmente ses prix, vous devriez pouvoir basculer vers DeepInfra. Si Anthropic ajoute une fonctionnalité dont vous avez besoin, vous devriez pouvoir l'essayer sans réécrire votre code. Si vous voulez exécuter localement pour la confidentialité, vous devriez pouvoir utiliser un modèle local.

La passerelle IA de FLIN fournit une interface unifiée vers huit fournisseurs. Votre code FLIN appelle ai_complete(), ai_embed() et ai_chat(). La passerelle route la requête vers le fournisseur configuré, traduit le format d'API et retourne une réponse normalisée. Changer de fournisseur se fait en une ligne dans flin.config.

L'API unifiée

Trois fonctions couvrent les opérations IA les plus courantes :

flin// Complétion de texte
response = ai_complete("Summarize this article: " + article.content, {
    max_tokens: 200,
    temperature: 0.3
})

// Complétion de chat
response = ai_chat([
    { role: "system", content: "You are a helpful assistant." },
    { role: "user", content: user_message }
])

// Embeddings
vector = ai_embed("comfortable office chair for long work sessions")

Ces fonctions marchent quel que soit le fournisseur configuré. L'API est la même que vous utilisiez GPT-4o, Claude, Gemini ou un modèle Llama local.

Configuration du fournisseur

Le fournisseur IA est configuré dans flin.config :

flin// flin.config
ai {
    provider = "openai"
    model = "gpt-4o-mini"
    embedding_model = "text-embedding-3-small"
    api_key = env("OPENAI_API_KEY")
}

Basculer vers un autre fournisseur :

flin// Anthropic
ai {
    provider = "anthropic"
    model = "claude-3-haiku"
    api_key = env("ANTHROPIC_API_KEY")
}

// DeepInfra
ai {
    provider = "deepinfra"
    model = "meta-llama/Meta-Llama-3-8B-Instruct"
    api_key = env("DEEPINFRA_API_KEY")
}

// Groq (pour la vitesse)
ai {
    provider = "groq"
    model = "llama3-70b-8192"
    api_key = env("GROQ_API_KEY")
}

// Local (pas de clé API nécessaire)
ai {
    provider = "local"
    model = "llama3"
    endpoint = "http://localhost:11434"
}

Le code de l'application ne change pas. Le même appel ai_complete() fonctionne avec chaque fournisseur.

Les huit fournisseurs pris en charge

FournisseurModèlesIdéal pour
OpenAIGPT-4o, GPT-4o MiniUsage général, vision
AnthropicClaude 3 Opus, Sonnet, HaikuContexte long, raisonnement
GoogleGemini Pro, Gemini FlashMultimodal, vitesse
MistralMistral Large, Medium, SmallRésidence des données européenne
CohereCommand R+, Embed v3Embeddings, RAG
GroqLlama 3, MixtralUltra-faible latence
DeepInfra50+ modèles openOptimisation des coûts
LocalOllama, llama.cppConfidentialité, hors ligne

Implémentation de la passerelle

La passerelle traduit entre le format unifié de FLIN et l'API spécifique de chaque fournisseur :

rustpub struct AiGateway {
    provider: Box<dyn AiProvider>,
    config: AiConfig,
}

pub trait AiProvider: Send + Sync {
    async fn complete(&self, prompt: &str, opts: &CompletionOptions) -> Result<String, AiError>;
    async fn chat(&self, messages: &[Message], opts: &ChatOptions) -> Result<String, AiError>;
    async fn embed(&self, text: &str) -> Result<Vec<f32>, AiError>;
}

impl AiGateway {
    pub fn new(config: &AiConfig) -> Result<Self, AiError> {
        let provider: Box<dyn AiProvider> = match config.provider.as_str() {
            "openai" => Box::new(OpenAiProvider::new(&config)?),
            "anthropic" => Box::new(AnthropicProvider::new(&config)?),
            "google" => Box::new(GoogleProvider::new(&config)?),
            "mistral" => Box::new(MistralProvider::new(&config)?),
            "cohere" => Box::new(CohereProvider::new(&config)?),
            "groq" => Box::new(GroqProvider::new(&config)?),
            "deepinfra" => Box::new(DeepInfraProvider::new(&config)?),
            "local" => Box::new(LocalProvider::new(&config)?),
            other => return Err(AiError::UnknownProvider(other.into())),
        };

        Ok(Self { provider, config })
    }
}

Le fournisseur Anthropic traduit vers le format d'Anthropic (qui utilise system comme paramètre séparé, pas comme message) :

rustimpl AiProvider for AnthropicProvider {
    async fn chat(&self, messages: &[Message], opts: &ChatOptions) -> Result<String, AiError> {
        let system = messages.iter()
            .find(|m| m.role == "system")
            .map(|m| m.content.clone());

        let user_messages: Vec<_> = messages.iter()
            .filter(|m| m.role != "system")
            .map(|m| json!({ "role": m.role, "content": m.content }))
            .collect();

        let mut body = json!({
            "model": self.model,
            "messages": user_messages,
            "max_tokens": opts.max_tokens.unwrap_or(1024),
        });

        if let Some(sys) = system {
            body["system"] = json!(sys);
        }

        // ... envoyer la requête à l'API Anthropic
    }
}

Chaînes de repli

FLIN prend en charge la configuration de repli pour la haute disponibilité :

flinai {
    provider = "openai"
    model = "gpt-4o-mini"
    api_key = env("OPENAI_API_KEY")

    fallback {
        provider = "deepinfra"
        model = "meta-llama/Meta-Llama-3-8B-Instruct"
        api_key = env("DEEPINFRA_API_KEY")
    }
}

Si le fournisseur principal échoue (limite de débit, erreur API, timeout), la passerelle réessaie automatiquement avec le fournisseur de repli. Le code de l'application n'est pas au courant du basculement.

Optimisation des coûts

Les différents fournisseurs ont des tarifications radicalement différentes :

FournisseurModèleCoût par 1M tokens
OpenAIGPT-4o Mini0,15 $ entrée / 0,60 $ sortie
AnthropicClaude 3 Haiku0,25 $ entrée / 1,25 $ sortie
DeepInfraLlama 3 8B0,06 $ entrée / 0,06 $ sortie
GroqLlama 3 70B0,59 $ entrée / 0,79 $ sortie

Pour la traduction de requêtes du moteur d'intentions, où la tâche est relativement simple, un modèle plus petit comme Llama 3 8B sur DeepInfra peut être 10 fois moins cher que GPT-4o avec une précision comparable. La passerelle de FLIN rend ce changement trivial.

Pourquoi une passerelle, pas une bibliothèque

L'alternative à une passerelle est des bibliothèques spécifiques aux fournisseurs : openai-sdk, anthropic-sdk, google-ai-sdk. Chacune avec sa propre API, sa propre gestion d'erreurs, ses propres types. Changer de fournisseur signifie réécrire chaque appel IA dans votre application.

La passerelle de FLIN fait de la sélection du fournisseur une décision de configuration, pas une décision de code. Votre logique applicative exprime ce qu'elle veut (« résumer ce texte », « classifier ce ticket », « embedder cette requête »), et la passerelle gère comment l'obtenir du fournisseur configuré.

Cette séparation des préoccupations est particulièrement importante pour le moteur d'intentions et la recherche sémantique, qui sont des fonctionnalités centrales du langage. Elles ne devraient pas cesser de fonctionner parce que vous avez basculé d'OpenAI à Anthropic.

Dans le prochain article, nous plongeons dans l'intégration FastEmbed -- comment FLIN génère des embeddings localement sans aucun appel API, permettant la recherche sémantique hors ligne et les applications privacy-first.


Ceci est la partie 118 de la série « Comment nous avons construit FLIN », documentant comment un CEO à Abidjan et un CTO IA ont conçu et construit un langage de programmation à partir de zéro.

Navigation de la série : - [117] Recherche sémantique et stockage vectoriel - [118] Passerelle IA : 8 fournisseurs, une seule API (vous êtes ici) - [119] Intégration FastEmbed pour les embeddings - [120] RAG : récupération, reclassement et attribution des sources

Share this article:

Responses

Write a response
0/2000
Loading responses...

Related Articles

Thales & Claude deblo

Le Step Zero ne suffisait pas : comment valider un constructeur sans valider le runtime a fait tomber toutes les sessions vocales de Déblo l’heure où nous avons livré le streaming caméra temps réel

La phase 14 a livré Déblo Eyes — streaming caméra temps réel via LiveKit vers Gemini Live native audio. Le premier deploy a fait tomber toutes les sessions vocales en production en quatre-vingt-dix secondes parce que notre Step 0 avait validé le constructeur sans exercer le runtime. Le build log de comment Déblo a eu des yeux, ce qu’un pré-vol incomplet a coûté, et quels points de polish ont été livrés ou reportés.

33 min May 20, 2026
debloclaude-opus-4.7claude-codegemini-live +25
Thales & Claude deblo

Le tiret cadratin qui a tué la production : comment un slogan marketing dans un header HTTP a fait tomber le chat de Déblo pendant 24 heures

Deux jours avant la soumission App Store, tout le produit chat de Déblo s’est cassé silencieusement. Pas de spinner, pas de toast, aucune erreur dans l’UI — juste un silence radio. L’incident de 24 heures se résumait à un seul « é » dans la valeur d’un header HTTP qui levait une UnicodeEncodeError avant qu’aucune requête vers OpenRouter ne quitte le backend. Post-mortem d’une fausse hypothèse, d’une trace Sentry, et d’un fix de six lignes qui a débloqué le lancement.

30 min May 19, 2026
debloclaude-opus-4.7claude-codeincident +19
Thales & Claude deblo

Six heures, d’une page blanche à la review Apple — Comment nous avons soumis Déblo à l’App Store, en direct

Marche à marche en direct de la soumission de Déblo à l’App Store iOS en six heures : ce que les validateurs d’Apple ont rejeté (un superscript Unicode), ce que nous avons corrigé (un Promotional Text gaspillé sur des marques tierces), et les rouages de l’ASO iOS que presque tout le monde rate.

30 min May 13, 2026
debloclaude-opus-4.7claude-codeapp-store +16