Aller au contenu principal

B14 - Bascule des providers

GroupeTechnologieStatutServicePhase de la feuille de routeContrats
B - Gestion des LLM et Model GatewayReplis LiteLLM + Routerà développerllm3-

Retour à l'index - English

Rôle et responsabilités​

Chaînes de repli qui ne franchissent jamais une région, un modèle ou une classification interdits.

Modèle de données​

Tables (schéma eai, chaque table tenant porte tenant_id uuid NOT NULL avec une politique RLS sur current_setting('app.tenant_id', true)::uuid) : eai.llm_routes, eai.audit_events.

Endpoints API​

  • POST /v1/routes/simulate
  • POST /v1/providers/{id}/disable
POST /v1/routes/simulate HTTP/1.1
Host: <control-plane-host>
X-API-Key: eai_xxx_secret
Accept-Language: fr
Content-Type: application/json

{"purpose": "support", "data_classification": "confidential", "region_allow": ["eu"]}
{"selected": "fake-gpt", "fallbacks": [], "strategy": "priority", "rejected": [], "route_id": "417d22b5-f725-4a5c-a6fe-128310c3d083"}

Les erreurs utilisent l'enveloppe commune {"error": {"code", "message", "message_i18n", "details", "request_id"}} ; les listes sont paginées avec limit et cursor.

Utilisation des SDK​

Python (enterprise_ai):

from enterprise_ai import EnterpriseAI

client = EnterpriseAI(base_url="<control-plane-url>", api_key="eai_xxx_secret")
items = client.routes.list()

TypeScript (@enterprise-ai/sdk):

import { EnterpriseAI } from "@enterprise-ai/sdk";

const eai = new EnterpriseAI({ baseUrl: "<control-plane-url>", apiKey: process.env.EAI_API_KEY });
const items = await eai.routes.list();

Java (enterprise-ai-java):

EnterpriseAIClient client = EnterpriseAIClient.builder()
.baseUrl("<control-plane-url>")
.apiKey(System.getenv("EAI_API_KEY"))
.build();
var items = client.routes().list();

Go (enterprise-ai-go):

client, _ := eai.NewClient(eai.WithBaseURL("<control-plane-url>"), eai.WithAPIKey(os.Getenv("EAI_API_KEY")))
items, err := client.Routes.List(ctx)

Configuration​

  • Environnement : EAI_DATABASE_URL, EAI_OTEL_EXPORTER_OTLP_ENDPOINT.
  • Valeurs Helm : controlPlane.enabled, controlPlane.replicas, controlPlane.resources, controlPlane.config, litellm.enabled, litellm.config.

Contrôles de sécurité​

  • Authentification par JWT OIDC, clé API tenant avec scopes, ou mTLS SPIFFE ; le tenant est résolu depuis l'identifiant, jamais depuis le corps.
  • Autorisation par décisions OpenFGA et OPA ; chaque mutation et décision écrit une ligne eai.audit_events chaînée par hash.
  • Les secrets ne sont jamais renvoyés par l'API ; TLS partout ; les politiques réseau Cilium restreignent qui peut joindre le service.
ContrôleApplication
Listes d'autorisation provider / modèle / régionPar tenant et projet dans eai.policies ; le Router ne sélectionne que des triplets (provider, modèle, région) autorisés
Classification des donnéeseai.data_classification de la requête doit être <= data_classification_max du modèle ; les données très sensibles (restricted, secret) restent sur des modèles locaux (vLLM)
DLPLa DLP Gateway (E02) inspecte puis masque ou tokenise les prompts avant tout appel distant
Isolation des secretsIdentifiants en écriture seule, stockés dans OpenBao, injectés dans LiteLLM lors de la synchronisation, jamais renvoyés par l'API ni journalisés
TLSTLS 1.2+ vers chaque provider, mTLS SPIFFE dans le cluster
Rétention chez le providerLe registre consigne les conditions de rétention / de non-conservation des données (zero data retention) ; les modèles sans conditions acceptables sont restreints
Politique de repliLes chaînes de repli sont filtrées par les mêmes listes : jamais de région, de modèle ou de classification interdits
Garde-fous de coûtEstimation et réservation de quota avant exécution (POST /v1/gateway/estimate, POST /v1/quotas/reserve), coupure du streaming pendant l'exécution quand le budget est atteint
Journalisation sans expositionPrompts et réponses journalisés uniquement selon la politique, masqués, jamais avec des identifiants
Kill switchPOST /v1/providers/{id}/disable et POST /v1/models/{model_id}/disable prennent effet dès l'appel suivant

Les modèles distants sont autorisés pour certains usages (données publiques ou internes, finalités approuvées) tandis que les données très sensibles restent sur des modèles locaux.

Observabilité​

  • Métriques : eai_provider_failover_requests_total, eai_provider_failover_errors_total, eai_provider_failover_latency_seconds (Prometheus).
  • Traces : spans OpenTelemetry eai.routes.* avec propagation W3C traceparent, spans IA envoyés à Opik.
  • Actions d'audit : route.create, route.update, route.delete, policy.evaluate.

Aspects FinOps​

Le coût d'exploitation est imputé par tenant et projet via les labels des Usage Events et les requêtes de ressources Kubernetes ; pas de coût direct par appel.

Modes de défaillance et résilience​

  • Déclencheurs de bascule : 429, 5xx, timeout, provider désactivé.
  • Chaque candidat est revérifié contre les listes et la classification ; s'il n'en reste aucun, l'appel échoue avec no_allowed_route, jamais de repli silencieux vers une région interdite.

Adoption autonome (client d'un client)​

Un client d'un client peut adopter cette brique seule avec le sous-client SDK Python client.routes (TS eai.routes, Java client.routes(), Go client.Routes). Déploiement minimal : Control Plane API + PostgreSQL + Keycloak (ou clés API), le Control Plane charge tous les domaines de services/control-plane/src/eai/domains ; les composants optionnels du chart se coupent dans deploy/helm/enterprise-ai/values.yaml (vllm.enabled, qdrant.enabled, nats.enabled, workers.enabled).

Tests d'acceptation​

  1. Un tenant ne peut ni lire ni modifier les ressources d'un autre tenant (test RLS).
  2. Chaque mutation produit un événement d'audit vérifiable par GET /v1/audit/verify.
  3. Les erreurs sont renvoyées en anglais et en français selon Accept-Language.