Aller au contenu

Projet indépendant de R&D · Cologne

Frontière probabiliste

Un composant probabiliste est borné et ne peut pas devenir directement une sortie de domaine faisant autorité.

Non normatif

Version du Companion
1.0
Se rapporte à COADF Core
2.2
Statut
À jour
Dernière relecture
Principes COADF
P-1, P-5

Propriété d'architecture

COADF P-1 énonce le minimum : un composant probabiliste renvoie une valeur accompagnée d'une confiance et de la méthode par laquelle la valeur a été obtenue, jamais une valeur nue, et il n'atteint jamais directement une sortie. Ce pattern porte sur la seconde moitié, celle que les mises en œuvre perdent. La réponse d'un modèle peut entrer dans le système. Ce qu'elle ne peut pas faire, c'est devenir, par quelque chemin que ce soit, ce que le système traite comme établi.

Trois conditions doivent tenir à la fois :

  • La sortie a un type qui lui est propre. Une proposition et un enregistrement faisant autorité sont des types différents, des tables différentes ou des messages différents. Le code qui détient l'un ne peut pas le passer là où l'autre est attendu sans une étape explicite que quelqu'un peut relire.
  • La frontière valide à l'exécution. Le contrat est vérifié à l'arrivée de la réponse, dans le processus qui la reçoit, quoi que l'expéditeur dise avoir vérifié.
  • La provenance voyage avec la valeur. La méthode, le modèle et sa révision, la révision du prompt et l'emplacement dans la source restent attachés à travers chaque étape, sérialisation comprise. Sans eux, P-4 ne peut pas reconstruire et P-5 ne peut pas déclarer.

P-1 demande aussi au composant d'indiquer une confiance. La façon dont la confiance est exprimée, attribuée et utilisée relève de P-2, que COADF publie seulement comme principe. Ce Companion ne la décrit pas, et rien de ce qui suit n'en dépend.

Pourquoi elle compte

La sortie d'un modèle provient d'un processus qu'on ne peut pas reproduire à partir de ses entrées comme on reproduit la sortie d'un parseur : l'échantillonnage, les mises à jour du modèle et les changements de prompt la font tous varier. C'est acceptable pour une proposition et inacceptable pour un fait. Le risque n'est pas qu'un modèle se trompe parfois ; tout se trompe parfois. Le risque est de perdre la capacité de dire quelles valeurs viennent d'où, parce que chaque contrôle ultérieur en dépend. Une barrière n'arrête que ce qu'elle voit, une déclaration ne nomme que ce qui est marqué, et une personne qui vérifie ne contrôle que ce qui pointe encore vers sa source.

La perte est rarement une décision. Elle survient sur une ligne de code ordinaire : une entité ORM remplie à partir du JSON du modèle parce que les noms de champs se trouvaient correspondre, un modèle de réponse qui laisse tomber la provenance parce que personne ne l'y a ajoutée, un import par lots qui contourne le formulaire où vivait la validation. Le pattern existe pour qu'on ne puisse pas écrire cette ligne sans s'en apercevoir.

Stratégies de mise en œuvre valables

L'isolation est architecturale, pas nécessairement physique

Les microservices ne sont pas nécessaires. La propriété tient quand aucun chemin de code ne permet au côté probabiliste de produire un objet faisant autorité, et un seul processus peut la tenir aussi bien qu'un réseau. La topologie se choisit pour ses propres raisons (mettre à l'échelle séparément une charge d'inférence, isoler la bibliothèque cliente d'un fournisseur, déployer indépendamment), puis la frontière se construit dans la forme choisie. Les quatre figures ci-dessous tiennent la même propriété sous quatre formes.

Architecture d'exemple · Non normative

Monolithe modulaire

Exemple d'architecture, non normatif : un monolithe modulaire dans lequel un client de modèle, un module frontière, un cœur du domaine et un adaptateur de classification partagent un seul processus, avec la piste d'audit et un service externe en dehors de celui-ci.Dans un seul processus : un client de modèle, marqué comme probabiliste, transmet sa réponse brute à un module frontière, qui transmet une proposition (Proposal) au cœur du domaine. Un adaptateur de classification, lui aussi dans le processus, peut transmettre un enrichissement au cœur du domaine, et il interroge un service de classification externe situé hors du processus. Le cœur du domaine écrit des entrées dans la piste d'audit, une base de données distincte. Le seul chemin du client de modèle vers le cœur du domaine passe par la frontière.Un seul processus, une unité déployableClientde modèleprobabilisteFrontièrecontrat typé,validation, provenanceCœur du domainepropositions séparéesdes enregistrementsvérifiésAdaptateurde classification,derrière un portPiste d'auditen ajout seulService externede classificationréponse bruteProposalentrées
  • Flux de données dans cet exemple
  • Facultatif : peut être indisponible
Un seul processus. La frontière est un module, et des contrats d'import empêchent le client de modèle d'atteindre le cœur du domaine autrement qu'en passant par elle.

Description textuelle. Dans un seul processus : un client de modèle, marqué comme probabiliste, transmet sa réponse brute à un module frontière, qui transmet une proposition (Proposal) au cœur du domaine. Un adaptateur de classification, lui aussi dans le processus, peut transmettre un enrichissement au cœur du domaine, et il interroge un service de classification externe situé hors du processus. Le cœur du domaine écrit des entrées dans la piste d'audit, une base de données distincte. Le seul chemin du client de modèle vers le cœur du domaine passe par la frontière.

Architecture d'exemple · Non normative

Orienté services

Exemple d'architecture, non normatif : un service d'inférence avec un client de modèle et une frontière, et un service de domaine avec sa propre frontière, son cœur du domaine, un adaptateur de classification et une piste d'audit.Un service d'inférence contient un client de modèle, marqué comme probabiliste, et une frontière qui valide ce qu'elle envoie. Il envoie, via HTTP et selon un contrat JSON, à un service de domaine, dont la propre frontière valide ce qu'elle reçoit et transmet une proposition (Proposal) au cœur du domaine. Le service de domaine contient aussi un adaptateur de classification, qui interroge un service externe et peut transmettre un enrichissement au cœur du domaine, ainsi que la piste d'audit, dans laquelle le cœur du domaine écrit des entrées. Le service d'inférence n'a aucune connexion à la piste d'audit.Service d'inférenceService de domaine et son stockageClientde modèleprobabilisteFrontièrevalide ce qu'elleenvoieFrontièrevalide ce qu'ellereçoitCœur du domainepropositions séparéesdes enregistrementsvérifiésAdaptateurde classificationPiste d'auditen ajout seulService externede classificationréponse bruteHTTP, JSONProposalentrées
  • Flux de données dans cet exemple
  • Facultatif : peut être indisponible
Deux services. Chaque côté valide : l'émetteur ce qu'il envoie, le récepteur ce qu'il reçoit. Le service d'inférence ne détient aucun identifiant d'accès au stockage du domaine.

Description textuelle. Un service d'inférence contient un client de modèle, marqué comme probabiliste, et une frontière qui valide ce qu'elle envoie. Il envoie, via HTTP et selon un contrat JSON, à un service de domaine, dont la propre frontière valide ce qu'elle reçoit et transmet une proposition (Proposal) au cœur du domaine. Le service de domaine contient aussi un adaptateur de classification, qui interroge un service externe et peut transmettre un enrichissement au cœur du domaine, ainsi que la piste d'audit, dans laquelle le cœur du domaine écrit des entrées. Le service d'inférence n'a aucune connexion à la piste d'audit.

Architecture d'exemple · Non normative

Piloté par les événements

Exemple d'architecture, non normatif : un worker d'inférence publie des propositions dans un topic, et un consommateur de domaine les valide à la réception avant que le cœur du domaine écrive des entrées d'audit.Un worker d'inférence contient un client de modèle, marqué comme probabiliste, et une frontière. Il publie un message dans un topic de propositions. Le corps du message porte le trace_id d'audit ; ses en-têtes portent le contexte d'exécution sous la forme d'un traceparent W3C. Un consommateur de domaine lit le topic, valide chaque message à la réception et transmet une proposition (Proposal) au cœur du domaine, qui écrit des entrées dans la piste d'audit.Worker d'inférenceConsommateur de domaineClient de modèleprobabilisteFrontièrevalide avantla publicationTopicpropositionsFrontièrevalide àla réceptionCœur du domainepropositions séparéesdes enregistrementsvérifiésPiste d'auditen ajout seulcorps : trace_iden-têtes : traceparentpublierconsommerProposalentrées
  • Flux de données dans cet exemple
Un topic entre les deux côtés. Le trace_id d'audit voyage dans le corps du message, en tant que partie du contrat ; le contexte d'exécution voyage dans les en-têtes du message.

Description textuelle. Un worker d'inférence contient un client de modèle, marqué comme probabiliste, et une frontière. Il publie un message dans un topic de propositions. Le corps du message porte le trace_id d'audit ; ses en-têtes portent le contexte d'exécution sous la forme d'un traceparent W3C. Un consommateur de domaine lit le topic, valide chaque message à la réception et transmet une proposition (Proposal) au cœur du domaine, qui écrit des entrées dans la piste d'audit.

Architecture d'exemple · Non normative

Déploiement cloud-native

Exemple d'architecture, non normatif : un namespace d'inférence, un namespace de service du modèle et un namespace d'enregistrements, dont le trafic sortant depuis l'inférence n'est autorisé que vers l'endpoint du modèle et vers le point d'entrée des propositions.Dans le namespace d'inférence, un pod d'inférence exécute le client de modèle et sa frontière. Il peut envoyer vers l'endpoint du modèle, dans le namespace de service du modèle, et vers le point d'entrée des propositions, dans le namespace des enregistrements, uniquement sur son port d'API. Le point d'entrée des propositions valide ce qu'il reçoit et transmet une proposition (Proposal) au cœur du domaine, qui écrit dans la piste d'audit et la base des enregistrements. Une note indique que le namespace d'inférence n'a ni route ni identifiant d'accès vers cette base de données.Namespace : inferenceNamespace : model-servingNamespace : recordsPod d'inférenceclient de modèleet frontièreEndpoint du modèlePoint d'entréedes propositions,valide àla réceptionCœur du domainepropositions séparéesdes enregistrements vérifiésPiste d'audit et basedes enregistrementsAucune route ni aucunidentifiant d'accès depuisle namespace inferencesortie autoriséeport d'API seulProposalentrées
  • Flux de données dans cet exemple
Trois namespaces. Les pods d'inférence peuvent joindre l'endpoint du modèle et le port d'API du point d'entrée des propositions ; aucune route et aucun identifiant d'accès n'atteint la base de données.

Description textuelle. Dans le namespace d'inférence, un pod d'inférence exécute le client de modèle et sa frontière. Il peut envoyer vers l'endpoint du modèle, dans le namespace de service du modèle, et vers le point d'entrée des propositions, dans le namespace des enregistrements, uniquement sur son port d'API. Le point d'entrée des propositions valide ce qu'il reçoit et transmet une proposition (Proposal) au cœur du domaine, qui écrit dans la piste d'audit et la base des enregistrements. Une note indique que le namespace d'inférence n'a ni route ni identifiant d'accès vers cette base de données.

Les quatre mêmes éléments dans chaque topologie

  • Des types distincts. Le côté probabiliste peut construire une proposition et rien d'autre. L'enregistrement faisant autorité n'est construit que par le code du domaine, à partir d'une proposition et de quelque chose que le côté probabiliste ne peut pas produire.
  • Une validation à l'exécution sur chaque côté récepteur. Un schéma strict : champs non déclarés rejetés, aucune coercition de type, vocabulaires fermés pour les valeurs catégorielles, longueurs bornées. Dans une topologie distribuée, chaque récepteur valide, côté domaine compris quand l'expéditeur est un service maison : « nous avons validé avant l'envoi » est une affirmation sur un autre déployable, peut-être sur une version plus ancienne de celui-ci.
  • La provenance dans le contrat. Déclarée, obligatoire, et préservée par chaque mapper et chaque sérialiseur en sortie.
  • Une étape de promotion explicite. La seule voie d'une proposition vers un enregistrement faisant autorité est une fonction, un endpoint ou une commande qui exige ce que le côté probabiliste ne peut pas fournir. Pour les valeurs dérivées par un modèle de langue, le fence public F-03 de COADF exige une vérification humaine avant qu'elles n'atteignent une sortie publiée. La promotion est elle-même consignée dans la piste d'audit.

Une validation déterministe autour d'une sortie stochastique

Les contrôles qui ne lisent que la valeur (sa forme, son vocabulaire, son unité, les plages que le domaine définit lui-même) s'exécutent avant que quiconque la regarde. Ils ne rendent pas une valeur vraie. Ils rendent impossible une valeur impossible, et ils le font chaque fois de la même façon, ce sur quoi la personne qui vérifie la valeur peut compter.

Options d'application, de la plus faible à la plus forte

Ce que chaque mécanisme d'application arrête, et ce qu'il n'arrête pas
MécanismeArrêteN'arrête pas
Séparation des typesLa promotion accidentelle dans du code qui passe la vérification de typesLes casts, le typage dynamique, la réflexion
Validation de schéma à l'exécutionLes réponses mal formées ou qui revendiquent tropUne valeur bien formée mais fausse
Test d'architecture sur les importsLe module probabiliste qui importe du code écrivant les enregistrementsLes imports faits par nom à l'exécution ; les chemins de données qui ne sont pas des imports
Droits de base de données par composantUn composant qui écrit dans le stockage faisant autoritéLes composants qui partagent des identifiants
Déploiement séparé et politique réseauUn composant déployé séparément qui atteint le stockage, de quelque façon que ce soitTout ce qui se trouve dans un même processus ; les clusters dont le plugin réseau n'applique pas la politique

La plupart des systèmes veulent toujours les trois premiers, et les deux derniers quand le composant probabiliste est déployé à part. Le profil Python et FastAPI met en œuvre les trois premiers ; le profil Cloud-native ajoute les deux derniers.

Modes de défaillance

  1. La sortie du modèle écrite directement dans le stockage faisant autorité

    La réponse est analysée dans l'entité que le reste du système lit comme un fait, parce que les champs correspondaient. Aucune ligne n'est fausse prise isolément. La frontière n'existe tout simplement pas.

  2. Des propositions impossibles à distinguer des données vérifiées

    Une table, un type, et un indicateur qui dit lequel est lequel. L'indicateur prend par défaut la valeur commode, ou bien le JSON du modèle lui-même peut le positionner.

  3. La provenance perdue en sortie

    Un mapper, un modèle de réponse ou un export omet la méthode et la source. Les frameworks qui filtrent la sortie selon un schéma déclaré le font sans bruit : FastAPI filtre une réponse selon son modèle de réponse, et le sérialiseur de Fastify laisse de côté les propriétés qu'un schéma de réponse ne liste pas, sauf si le schéma autorise des propriétés supplémentaires.

  4. Une validation seulement dans l'interface utilisateur

    Le formulaire valide. L'import par lots, le script d'administration et le second client, non.

  5. Les systèmes en aval ne distinguent pas l'inféré du vérifié

    Le format d'export n'a pas de champ pour la méthode : le système suivant reçoit une valeur et rien d'autre, et chacun de ses contrôles est aveugle à la différence.

  6. La réponse brute crue sans validation à l'exécution

    Un cast en TypeScript, un dictionnaire en Python, un mapper permissif en Java : le contrat existe dans les types du code et nulle part dans son comportement. Les annotations de type de TypeScript sont effacées à la compilation, et ses typages standard déclarent le résultat de JSON.parse comme any.

  7. La coercition masque l'erreur du modèle

    Une analyse laxiste transforme "12" en 12 et "true" en True. Le nombre a l'air juste et n'a jamais été un nombre. Le mode strict de Pydantic refuse cette coercition ; la configuration par défaut du validateur de Fastify active la coercition de types. Il faut savoir lequel des deux est en service.

  8. La réparation silencieuse

    La réponse échoue à la validation, alors l'appel est relancé jusqu'à ce qu'une réponse passe, et seule la dernière est conservée. Les échecs étaient des éléments de preuve sur le modèle, et ils ont disparu.

  9. La validation contournée pour la vitesse

    Une optimisation qui construit des objets sans validation devient le chemin le plus facile, puis le contournement. model_construct de Pydantic crée un modèle sans le valider, exactement comme documenté.

Vérification

  • Test unitaire

    Réussit quand : Chaque réponse mal formée est rejetée : un champ non déclaré, un type coercible, une provenance manquante, un attribut que personne n'a demandé.

    Preuve de dents : Supprimer une contrainte dans une copie jetable (par exemple la règle qui rejette les champs non déclarés) : le test correspondant doit échouer.

  • Test d'architecture

    Réussit quand : Le module probabiliste n'a aucun chemin d'import vers le code qui écrit les enregistrements faisant autorité.

    Preuve de dents : Ajouter l'import interdit dans une copie jetable : le contrat échoue et le build s'arrête.

  • Test de contrat

    Réussit quand : Producteur et consommateur s'accordent sur le schéma de proposition, avec les champs de provenance obligatoires.

    Preuve de dents : Retirer un champ de provenance du schéma du producteur : le test de contrat du consommateur échoue.

  • Test d'intégration

    Réussit quand : Quand le composant probabiliste est déployé à part, ses identifiants ne peuvent pas écrire dans le stockage faisant autorité.

    Preuve de dents : Tenter l'écriture avec ces identifiants : la base de données la refuse.

  • Test de bout en bout

    Réussit quand : Une sortie dont un attribut provient d'une proposition que personne n'a vérifiée ne peut pas être publiée.

    Preuve de dents : Planter une proposition non vérifiée et demander la publication : refus, et le refus figure dans la piste d'audit.

Réalisations alternatives

  • Des interfaces de suggestion seule. La sortie du modèle est montrée à une personne comme une suggestion et n'est jamais stockée comme valeur. Simple et solide ; on renonce à la traçabilité de ce qui a été suggéré, à moins de consigner aussi les suggestions.
  • Un contrat partagé, neutre vis-à-vis du langage (JSON Schema, Protocol Buffers), au lieu de modèles natifs du langage. Mieux entre langages ; la question de la rigueur se déplace dans le schéma, où les propriétés supplémentaires et les formats doivent être décidés explicitement.
  • Les modes de sortie structurée des API de modèles. Ils réduisent les réponses mal formées côté producteur. Ils ne dispensent pas le consommateur de valider, parce que le consommateur ne peut pas vérifier comment le producteur a été configuré.
  • Un stockage séparé pour les propositions et les enregistrements, deux tables ou deux stockages plutôt qu'une table avec un statut. Plus lourd, et la séparation devient visible dans chaque requête que quiconque écrit.

Limites

  • La frontière contrôle où la sortie d'un modèle peut aller. Elle ne rend pas cette sortie correcte, et une valeur bien formée mais fausse passe chaque contrôle de ce pattern.
  • La séparation des types arrête les accidents, pas l'intention. Un développeur disposant d'un accès en écriture au domaine peut construire à la main un objet faisant autorité ; ce sont la revue de code et la piste d'audit qui rendent cela visible.
  • Ce pattern ne dit pas quand une proposition a besoin d'une personne, ni comment la confiance est exprimée. Cela relève de P-2 et de P-3, que COADF publie seulement comme principes.
  • La validation ne vaut que ce que vaut le contrat. Un schéma permissif, validé strictement, reste permissif.

Sources

COADF Engineering Companion 1.0 · non normatif · se rapporte à COADF Core 2.2

Droits de publication réservés. Aucune licence publique n'est accordée à ce jour pour le COADF Engineering Companion 1.0 ni pour ses exemples de référence.

Statut de propriété intellectuelle et de publication