Skip to content

Le rôle de la passerelle

This content is not available in your language yet.

Un assistant de code pourrait appeler le fournisseur de modèles directement depuis le poste du développeur. C’est le chemin le plus court, et Lemniscate ne le prend pas : les requêtes passent par llm-gateway, un service que vous déployez dans votre périmètre.

Ce détour coûte un composant à exploiter. Voici ce qu’il achète.

C’est la raison principale, et elle est structurelle.

Un appel direct suppose que la clé du fournisseur soit posée sur chaque poste : dans un fichier de configuration, une variable d’environnement, un trousseau. À partir de là, elle est copiable, elle part avec le portable, et elle survit au départ de la personne. La révoquer veut dire la révoquer partout à la fois.

Avec la passerelle, le développeur détient une clé qui lui est propre et qui ne vaut que contre votre passerelle. Au moment de relayer, la passerelle retire les crédentiels de l’appelant des en-têtes — authorization et x-api-key — puis pose à la place la clé du fournisseur, lue dans son propre environnement. Le poste ne voit jamais cette clé, et rien de ce qui part du poste ne permet de la reconstituer.

La clé du fournisseur n’est pas non plus en base. La base enregistre le nom de la variable d’environnement qui la porte et l’en-tête HTTP dans lequel la déposer ; la valeur reste dans l’environnement du processus. Une copie de la base ne livre donc aucune clé de fournisseur — et une variable absente produit une erreur 500 qui nomme la variable manquante, plutôt qu’un échec opaque.

Côté comptes, la base ne garde qu’un condensat SHA-256 de la clé, plus un fragment affichable qui permet de reconnaître une clé sans pouvoir la relire.

Retirer un accès est une opération, pas une campagne

Section intitulée « Retirer un accès est une opération, pas une campagne »

Comme chaque personne a sa propre clé, la console d’administration peut agir sur une seule d’entre elles :

  • rotation — la clé est remplacée, le compte et son historique d’usage sont conservés, l’ancienne clé cesse de fonctionner ;
  • désactivation — un compte dont des appels sont journalisés ne se supprime pas, il se désactive, ce qui préserve l’attribution des appels déjà facturés ;
  • retrait du plan — un compte sans plan est refusé, ce qui bloque sans effacer.

Aucune de ces opérations ne touche les autres postes, et aucune ne demande de redéployer la passerelle : celle-ci relit la base à chaque requête, sans cache.

Les plafonds sont appliqués là où passe la dépense

Section intitulée « Les plafonds sont appliqués là où passe la dépense »

Un plafond posé côté client est une convention. Un plafond posé sur le chemin de la requête est une contrainte.

Chaque compte porte un plan, et chaque plan porte un plafond mensuel en euros. À chaque requête relayée, la passerelle recalcule la dépense du mois en cours en agrégeant request_logs avec les prix par token des modèles, sur une fenêtre qui commence au premier jour du mois. Au-delà du plafond, la requête est refusée avec un statut 402.

Trois états, à ne pas confondre :

État du compte Comportement
aucun plan rattaché refusé, statut 403
plan avec un plafond refusé au-delà, statut 402
plan sans plafond jamais refusé pour cause de dépense

Le piège vaut d’être connu : après jointure, « aucun plan » et « plan illimité » produisent tous les deux un plafond vide. Seul le rattachement au plan distingue les deux, et ce sont des résultats opposés.

Sur un poste construit avec le profil on-premise, les appels aux modèles sont le seul flux sortant — voir Où passent les données. Et ce flux ne va pas chez un fournisseur : il va chez vous.

Ce qui en découle pour l’exploitation :

  • la règle de pare-feu à écrire pour les postes tient en une destination, la passerelle, au lieu d’une liste de domaines de fournisseurs à tenir à jour ;
  • la sortie vers Internet, si vous en ouvrez une, part d’un seul hôte, celui que vous choisissez, dans le segment que vous choisissez ;
  • un fournisseur hébergé sur site — un serveur de modèles dans votre réseau — se déclare comme n’importe quel autre fournisseur, et le poste ne change pas de configuration pour autant.

Le client n’appelle pas un modèle, il appelle un endpoint : un nom que vous publiez et qui désigne un modèle chez un fournisseur. La passerelle écrase le champ model du corps par celui de l’endpoint.

Rediriger un endpoint vers un autre modèle est donc une modification faite dans la console, qui prend effet sur la requête suivante, sans qu’aucun poste soit reconfiguré. Changer de fournisseur pour cause de prix, de disponibilité ou de politique interne cesse d’être une opération de parc.

Une explication honnête doit aussi dire où s’arrête le composant.

  • Elle ne termine pas TLS. Elle écoute en HTTP. La terminaison TLS est à la charge de l’infrastructure qui l’accueille — ingress, répartiteur de charge, proxy inverse. Ce n’est pas un détail de déploiement : sans elle, les clés des comptes circulent en clair sur votre réseau.
  • request_logs est un fait de facturation, pas un journal d’audit. La table porte l’horodatage, le compte, l’endpoint, le modèle, la latence et les tokens — de quoi calculer un coût et appliquer un plafond. Elle ne porte ni contrôle d’intégrité, ni politique de rétention, et ses clés étrangères restent modifiables. Une supervision de sécurité se construit à côté, pas dessus.
  • Elle n’expose pas de route de santé ni de version. Sa seule route est la route de relais.

Ces limites sont des propriétés du composant, pas des surprises : elles définissent ce que l’infrastructure d’accueil doit apporter.

llm-gateway, gateway-db et gateway-admin sont séparés parce qu’ils ne courent pas les mêmes risques.

La passerelle est sur le chemin de chaque requête : elle doit rester petite, et elle détient les clés des fournisseurs. La console est un outil d’exploitation consulté quelques fois par semaine, et elle n’a aucune raison de connaître ces clés — elle ne parle qu’à la base. La base, elle, est le seul état durable, donc le seul objet à sauvegarder.

Le découpage se lit dans les flux : la console n’appelle jamais la passerelle, la passerelle n’appelle jamais la console. Elles se rencontrent dans la base. Le schéma d’ensemble est dans Architecture.