Concevoir des Systemes IA sans Vendor Lock-In : Quoi Abstraire (et Quoi Ne Pas Abstraire)
Comment concevoir des architectures IA qui survivent aux changements de fournisseur. Couches d'abstraction, portabilite des prompts, routage multi-modeles, developpement pilote par l'evaluation, et quand le lock-in est le bon choix.
Le Piege du Lock-In
Tout projet IA commence avec un seul fournisseur. OpenAI, Anthropic, ou un modele local. Le SDK entre dans le code. Les fonctionnalites specifiques au fournisseur (format d'appel de fonctions, mode JSON, comportement du prompt systeme) se retrouvent integrees dans la logique metier. Six mois plus tard, tu veux changer de fournisseur (cout, performance, conformite) et tu decouvres que la migration necessite de reecrire la moitie de l'application.
Nous avons construit des systemes IA qui utilisent plusieurs fournisseurs simultanement et avons change de fournisseur en cours de projet sans toucher a la logique metier. Cet article couvre l'architecture qui rend cela possible et les vrais compromis que ca implique.
Pour des patterns d'architecture IA plus larges, consulte notre guide sur les systemes IA et notre guide d'orchestration IA.
Ce Qui Cree le Lock-In
| Source de Lock-In | Exemple | Severite |
|---|---|---|
| Couplage SDK | openai.chat.completions.create() dans 50 fichiers | Elevee |
| Format de prompt | Prompts optimises pour le comportement de GPT-4, echouent sur Claude | Elevee |
| Modeles fine-tunes | Modele entraine sur tes donnees, heberge par le fournisseur | Tres Elevee |
| Fonctionnalites proprietaires | Assistants API, format d'appel de fonctions, mode JSON | Moyenne |
| Lock-in des embeddings | 100K documents indexes avec text-embedding-3-small, incompatibles avec d'autres modeles | Tres Elevee |
| Architecture liee aux rate limits | Systeme concu autour des rate limits et du batching specifiques a OpenAI | Basse |
La Couche d'Abstraction Qui Fonctionne
Une bonne couche d'abstraction a trois composants : une interface unifiee pour les appels de modeles, une couche de gestion des prompts, et un framework d'evaluation.
// Interface LLM unifiee
interface LlmProvider {
generate(request: LlmRequest): Promise<LlmResponse>;
stream(request: LlmRequest): AsyncIterable<LlmChunk>;
embed(texts: string[]): Promise<number[][]>;
}
interface LlmRequest {
model: string;
messages: Message[];
temperature?: number;
maxTokens?: number;
responseFormat?: 'text' | 'json';
tools?: ToolDefinition[];
}
interface LlmResponse {
text: string;
usage: { promptTokens: number; completionTokens: number };
finishReason: string;
model: string;
provider: string;
latencyMs: number;
}
Chaque fournisseur implemente cette interface :
class OpenAiProvider implements LlmProvider {
async generate(request: LlmRequest): Promise<LlmResponse> {
const response = await this.client.chat.completions.create({
model: request.model,
messages: this.convertMessages(request.messages),
temperature: request.temperature,
max_tokens: request.maxTokens,
response_format: request.responseFormat === 'json'
? { type: 'json_object' } : undefined,
});
return this.convertResponse(response);
}
}
class AnthropicProvider implements LlmProvider {
async generate(request: LlmRequest): Promise<LlmResponse> {
const response = await this.client.messages.create({
model: request.model,
system: this.extractSystemMessage(request.messages),
messages: this.convertMessages(request.messages),
temperature: request.temperature,
max_tokens: request.maxTokens ?? 4096,
});
return this.convertResponse(response);
}
}
La logique metier utilise l'interface, jamais le SDK du fournisseur directement :
// Logique metier : agnostique du fournisseur
async function generateCustomerResponse(ctx: Context, ticket: string): Promise<string> {
const provider = ctx.getLlmProvider(); // resolu depuis la config
const response = await provider.generate({
model: ctx.getModelForUseCase('customer-support'),
messages: [
{ role: 'system', content: SUPPORT_SYSTEM_PROMPT },
{ role: 'user', content: ticket },
],
temperature: 0.3,
});
return response.text;
}
Passer d'OpenAI a Anthropic : change la config. Zero modification de code dans la logique metier.
Le Probleme de la Portabilite des Prompts
Les prompts ne sont pas portables d'un modele a l'autre. Un prompt optimise pour GPT-4 peut donner de moins bons resultats sur Claude, et inversement. Les modeles interpretent les instructions differemment, gerent les cas limites differemment, et ont des forces differentes.
La solution : des variantes de prompt par famille de modeles.
const SUPPORT_PROMPTS: Record<string, string> = {
'openai': `You are a customer support assistant. Be concise and helpful.
When you don't know the answer, say so clearly.
Always reference the customer's order number.`,
'anthropic': `You are a customer support assistant.
<instructions>
- Be concise and helpful
- When you don't know the answer, say so clearly
- Always reference the customer's order number
</instructions>`,
'local': `### System
You are a customer support assistant.
### Rules
1. Be concise and helpful
2. When you don't know the answer, say so clearly
3. Always reference the customer's order number`,
};
function getPrompt(useCase: string, provider: string): string {
return PROMPTS[useCase][provider] || PROMPTS[useCase]['default'];
}
Ca ajoute un cout de maintenance (plusieurs versions de prompts), mais c'est la realite. Un seul prompt pour tous les modeles signifie accepter une qualite degradee sur au moins un modele.
Routage Multi-Modeles
Chaque tache a des exigences differentes. La classification a besoin de rapidite. La generation a besoin de qualite. L'embedding a besoin de coherence. Dirige chaque tache vers le bon modele.
const MODEL_ROUTING: Record<string, ModelConfig> = {
'classification': {
primary: { provider: 'openai', model: 'gpt-4o-mini' },
fallback: { provider: 'anthropic', model: 'claude-haiku-4-5-20251001' },
reason: 'Fast, cheap, good enough for classification',
},
'generation': {
primary: { provider: 'anthropic', model: 'claude-sonnet-4-20250514' },
fallback: { provider: 'openai', model: 'gpt-4o' },
reason: 'Best quality for long-form generation',
},
'embedding': {
primary: { provider: 'openai', model: 'text-embedding-3-small' },
fallback: null, // Impossible de changer de modele d'embedding sans re-indexer
reason: 'Consistency: all embeddings must use the same model',
},
'summarization': {
primary: { provider: 'anthropic', model: 'claude-haiku-4-5-20251001' },
fallback: { provider: 'openai', model: 'gpt-4o-mini' },
reason: 'Fast and cheap for summaries',
},
};
La config de routage est separee de la logique metier. Changer le modele qui gere le resume est un changement de config, pas un changement de code.
Lock-In des Embeddings : Le Plus Difficile a Briser
Les embeddings sont la forme de lock-in la plus forte. Une fois que tu as indexe 100K documents avec text-embedding-3-small, changer de modele d'embedding necessite de re-indexer tout. Les vecteurs sont incompatibles d'un modele a l'autre (dimensions differentes, espaces semantiques differents).
Mesures d'attenuation :
- Stocke les documents sources a cote des embeddings (pour pouvoir re-indexer)
- Trace quel modele d'embedding a ete utilise par document
- Prevois le budget pour le re-embedding lors d'un changement de fournisseur
- Envisage des modeles d'embedding open-source (sentence-transformers) pour la portabilite
Pour approfondir les patterns de recherche vectorielle et la gestion des embeddings, consulte notre guide d'architecture de recherche vectorielle et notre guide des systemes RAG d'entreprise.
Developpement Pilote par l'Evaluation
La cle pour changer de fournisseur en toute securite : evalue par rapport aux taches, pas par rapport aux modeles. Si ta suite d'evaluation teste "est-ce que la reponse traite correctement le probleme du client ?" plutot que "est-ce que la sortie correspond au format de GPT-4 ?", tu peux changer de modele en toute confiance.
interface EvalCase {
input: string;
expectedBehavior: string; // Ce que la sortie devrait FAIRE, pas ce qu'elle devrait DIRE
criteria: EvalCriterion[];
}
interface EvalCriterion {
name: string;
check: (output: string, context: EvalCase) => boolean | number;
}
const SUPPORT_EVALS: EvalCase[] = [
{
input: "I haven't received my order #12345",
expectedBehavior: "Acknowledge the issue, reference order number, offer next steps",
criteria: [
{ name: 'references_order', check: (out) => out.includes('12345') },
{ name: 'acknowledges_issue', check: (out) => /sorry|apologize|understand/i.test(out) },
{ name: 'offers_action', check: (out) => /check|investigate|track|follow up/i.test(out) },
{ name: 'reasonable_length', check: (out) => out.length > 50 && out.length < 500 },
],
},
];
// Lancer les evals sur n'importe quel modele
async function runEvalSuite(provider: LlmProvider, model: string): Promise<EvalResults> {
const results = [];
for (const evalCase of SUPPORT_EVALS) {
const output = await provider.generate({
model,
messages: [
{ role: 'system', content: SUPPORT_SYSTEM_PROMPT },
{ role: 'user', content: evalCase.input },
],
});
const scores = evalCase.criteria.map(c => ({
name: c.name,
passed: c.check(output.text, evalCase),
}));
results.push({ input: evalCase.input, scores });
}
return summarize(results);
}
Lance la suite d'evaluation avant de changer de modele. Si le nouveau modele passe avec des scores acceptables, la migration est sure. Sinon, tu sais exactement quels comportements se sont degrades.
Notre guide sur l'observabilite IA couvre les metriques a surveiller en production pour ce type de transitions. Tu peux aussi explorer notre approche du design de workflows IA pour structurer tes pipelines de maniere modulaire.
Ce Qu'il Ne Faut PAS Abstraire
Tout ne doit pas etre abstrait. La sur-abstraction ajoute de la complexite sans benefice.
| Ne Pas Abstraire | Pourquoi |
|---|---|
| Modele d'embedding (dans un projet) | Les vecteurs sont incompatibles. L'abstraction n'aide pas. |
| Specificites du fine-tuning | Le fine-tuning est intrinsequement lie au fournisseur |
| Optimisations specifiques au fournisseur | Le batching, le cache, la gestion des rate limits different par fournisseur |
| Details du format de streaming | A gerer dans l'adaptateur du fournisseur, pas dans l'abstraction |
L'abstraction devrait couvrir : la selection du modele, le routage des prompts, le parsing des reponses, le suivi des couts, et la logique de fallback. Elle ne devrait PAS essayer de faire en sorte que tous les fournisseurs se comportent de maniere identique. Ce n'est pas le cas, et pretendre que si cree des bugs.
Ce pattern s'inscrit dans une approche plus large d'architecture logicielle et de conception de logiciels robustes. Si tu travailles sur des systemes multi-agents, notre guide d'architecture multi-agents couvre les strategies de routage a un niveau superieur.
Quand le Lock-In Est le Bon Choix
Parfois, se verrouiller chez un fournisseur est la bonne decision business :
- Le fine-tuning necessite un engagement chez un seul fournisseur. Le modele entraine n'est pas portable.
- Les remises sur volume d'un seul fournisseur peuvent reduire les couts de maniere significative.
- La conformite peut exiger un fournisseur specifique (residence des donnees, certifications).
- La rapidite de mise sur le marche implique d'utiliser les fonctionnalites specifiques au fournisseur sans le surcharge de l'abstraction.
L'essentiel : prends la decision de lock-in consciemment, pas accidentellement. Si tu choisis d'utiliser l'Assistants API d'OpenAI parce que ca t'economise 3 mois de developpement, c'est un compromis valide. Si tu l'utilises parce que tu n'as pas reflechi a l'abstraction, c'est de la dette technique.
Pour en savoir plus sur la conformite et les implications RGPD de tes choix de fournisseur IA, consulte notre guide de conformite RGPD pour l'IA et notre page RGPD.
Erreurs Courantes
-
SDK du fournisseur dans la logique metier.
openai.chat.completions.create()disperse dans 50 fichiers rend la migration impossible. Utilise une couche d'abstraction. -
Un seul prompt pour tous les modeles. Les prompts sont specifiques au modele. Maintiens des variantes par famille de modeles. Accepte le cout de maintenance.
-
Tout abstraire. La sur-abstraction ajoute de la complexite. Abstrait l'interface, pas les mecanismes internes.
-
Pas de suite d'evaluation. Sans evals automatisees, tu ne peux pas savoir si un changement de modele degrade la qualite avant que les utilisateurs se plaignent.
-
Ignorer le lock-in des embeddings. Changer de modele d'embedding necessite de re-indexer chaque document. Prevois ce cout.
-
Le lock-in accidentel. Le pire. Utiliser des fonctionnalites specifiques au fournisseur sans realiser que tu crees une dependance.
Notre guide sur les modes de defaillance de l'IA couvre d'autres pieges courants dans les systemes IA en production, et le guide de gouvernance IA t'aide a structurer les decisions autour du choix de fournisseur.
Points Cles a Retenir
-
Abstrait l'interface, pas l'implementation. Une interface
LlmProviderunifiee avec des adaptateurs specifiques par fournisseur. La logique metier appelle l'interface. -
Les prompts ne sont pas portables. Maintiens des variantes de prompt par famille de modeles. Un seul prompt pour tous les modeles signifie une qualite degradee quelque part.
-
Dirige chaque tache vers le bon modele. La classification vers un modele rapide, la generation vers un modele precis, les embeddings vers un modele coherent. Pilote par la config, pas par le code.
-
Evalue par rapport aux taches, pas aux modeles. Si ta suite d'evaluation teste le comportement ("est-ce qu'il reference le numero de commande ?") plutot que le format, tu peux changer de modele en confiance.
-
Les embeddings sont le lock-in le plus difficile a briser. Stocke les documents sources. Trace quel modele a ete utilise. Prevois le budget pour le re-embedding.
-
Parfois le lock-in est le bon choix. Fine-tuning, remises sur volume et conformite peuvent le justifier. Que ce soit une decision consciente.
Nous concevons des architectures IA agnostiques des fournisseurs dans le cadre de nos services IA et de notre practice de consulting. Explore nos solutions pour voir comment nous appliquons ces patterns, ou consulte nos cas d'utilisation concrets. Si tu as besoin d'aide pour ton architecture IA, parle a notre equipe ou demande un devis.
Sujets couverts
Guides connexes
Guide Entreprise des Systèmes d'IA Agentiques
Guide technique des systemes d'IA agentiques en entreprise. Decouvre l'architecture, les capacites et les applications des agents IA autonomes.
Lire le guideLe Guide Complet de l'Orchestration IA
Guide technique pour orchestrer plusieurs modeles IA en production. Apprends le routage, la selection de modeles, le fallback et le load balancing.
Lire le guideCommerce Agentique : Comment laisser les agents IA acheter en toute securite
Comment concevoir un commerce agentique gouverne. Moteurs de politiques, portes d'approbation HITL, reçus HMAC, idempotence, isolation multi-tenant et le protocole Agentic Checkout complet.
Lire le guidePrêt à construire des systèmes IA prêts pour la production ?
Notre équipe est spécialisée dans les systèmes IA prêts pour la production. Discutons de comment nous pouvons aider.
Démarrer une conversation