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
| Fournisseur | Modèles | Idéal pour |
|---|---|---|
| OpenAI | GPT-4o, GPT-4o Mini | Usage général, vision |
| Anthropic | Claude 3 Opus, Sonnet, Haiku | Contexte long, raisonnement |
| Gemini Pro, Gemini Flash | Multimodal, vitesse | |
| Mistral | Mistral Large, Medium, Small | Résidence des données européenne |
| Cohere | Command R+, Embed v3 | Embeddings, RAG |
| Groq | Llama 3, Mixtral | Ultra-faible latence |
| DeepInfra | 50+ modèles open | Optimisation des coûts |
| Local | Ollama, llama.cpp | Confidentialité, 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 :
| Fournisseur | Modèle | Coût par 1M tokens |
|---|---|---|
| OpenAI | GPT-4o Mini | 0,15 $ entrée / 0,60 $ sortie |
| Anthropic | Claude 3 Haiku | 0,25 $ entrée / 1,25 $ sortie |
| DeepInfra | Llama 3 8B | 0,06 $ entrée / 0,06 $ sortie |
| Groq | Llama 3 70B | 0,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