Aller au contenu principal

G-13 Orchestrateur qualité

Brique G de la plateforme Enterprise AI. Technologie : composant développé qui orchestre G-09, G-10, les contrôles de politique et les approbations en gates bloquantes. Version anglaise : ../../en/bricks/G-13-quality-orchestrator.md.

Rôle et responsabilités​

  • Décider si une version d'agent, prompt, modèle ou skill peut être promue dans un environnement.
  • Collecter les identifiants de preuves et écrire la décision de gate dans la chaîne d'audit.

Position et interactions​

  • Chemin d'exécution : workflow (pipeline de promotion).
  • Appelé par la CI (H-15), par la CLI (enterprise-ai test, publish) et par l'application de manifestes en prod.

Part open source et part développée​

  • Open source réutilisé : Aucun : code d'orchestration au-dessus de Ragas, Promptfoo, garak.
  • Développé dans la plateforme : Composant complet : définitions de gates par environnement, règles de fraîcheur, dérogation via approbations.

Modèle de données​

Tables du Control Plane (schéma eai) : eai.eval_suites, eai.eval_runs, eai.redteam_runs, eai.audit_events.

Chaque table de tenant a tenant_id uuid NOT NULL et une politique de sécurité au niveau des lignes sur current_setting('app.tenant_id', true)::uuid. ClickHouse usage_events est la réplique analytique de eai.usage_events (ReplacingMergeTree par event_id).

Contrat : contracts/v1/evaluation-contract.schema.json (schema_version 1.0). L'usage est toujours remonté avec contracts/v1/usage-event.schema.json, l'audit avec contracts/v1/audit-event.schema.json.

Endpoints d'API​

MéthodeChemin
POST/v1/evaluations/gates/check
POST/v1/evaluations/runs
POST/v1/redteam/runs

POST /v1/evaluations/gates/check​

Requête :

{
"target": {
"type": "agent",
"ref": "agt_ap",
"version": "1.4.0"
},
"suite_ids": [
"evs_12"
],
"run_missing": true
}

Réponse :

{
"passed": false,
"reasons": [
"redteam run missing for version 1.4.0"
],
"evidence": [
"evr_77"
]
}

POST /v1/evaluations/runs​

Requête :

{
"suite_id": "evs_12",
"target": {
"type": "agent",
"ref": "agt_ap",
"version": "1.4.0"
}
}

Réponse :

{
"evaluation_id": "evr_77",
"status": "running"
}

POST /v1/redteam/runs​

Requête :

{
"target": {
"type": "agent",
"ref": "agt_ap",
"version": "1.4.0"
},
"engine": "garak",
"probes": [
"promptinject",
"dan",
"leakreplay"
],
"max_attack_success_rate": 0.05
}

Réponse :

{
"id": "rtr_5",
"status": "running"
}

Exemples SDK​

Python​

from enterprise_ai import EnterpriseAI

client = EnterpriseAI(base_url="<control-plane-url>", api_key="eai_live_xxx", tenant="acme", locale="fr")
client.evaluation.check_gate(target={"type": "agent", "ref": "agt_ap", "version": "1.4.0"})
client.evaluation.run(suite_id="evs_12", target={"type": "agent", "ref": "agt_ap", "version": "1.4.0"})
client.evaluation.redteam(target={"type": "agent", "ref": "agt_ap"}, engine="garak", probes=["promptinject", "dan"])

TypeScript​

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

const client = new EnterpriseAI({ baseUrl: "<control-plane-url>", apiKey: process.env.EAI_API_KEY, tenant: "acme", locale: "fr" });
await client.evaluations.checkGate({ target: { type: "agent", ref: "agt_ap", version: "1.4.0" }, suite_ids: ["evs_12"] });
await client.evaluations.createRun({ suite_id: "evs_12", target: { type: "agent", ref: "agt_ap", version: "1.4.0" } });
await client.redteam.createRun({ target: { type: "agent", ref: "agt_ap" }, engine: "garak", probes: ["promptinject", "dan"] });

Java​

EnterpriseAIClient client = EnterpriseAIClient.builder()
.baseUrl("<control-plane-url>")
.apiKey(System.getenv("EAI_API_KEY"))
.tenant("acme")
.locale(Locale.FRENCH)
.build();
client.evaluations().checkGate(Map.of("target", Map.of("type", "agent", "ref", "agt_ap", "version", "1.4.0"), "suite_ids", List.of("evs_12")));
client.evaluations().createRun(Map.of("suite_id", "evs_12", "target", Map.of("type", "agent", "ref", "agt_ap", "version", "1.4.0")));
client.redteam().createRun(Map.of("target", Map.of("type", "agent", "ref", "agt_ap"), "engine", "garak", "probes", List.of("promptinject", "dan")));

Go​

client, err := eai.NewClient(eai.WithBaseURL("<control-plane-url>"), eai.WithAPIKey(os.Getenv("EAI_API_KEY")), eai.WithTenant("acme"), eai.WithLocale("fr"))
if err != nil { log.Fatal(err) }
ctx := context.Background()
_, err = client.Evaluations.CheckGate(ctx, map[string]any{"target": map[string]any{"type": "agent", "ref": "agt_ap", "version": "1.4.0"}})
_, err = client.Evaluations.CreateRun(ctx, map[string]any{"suite_id": "evs_12", "target": map[string]any{"type": "agent", "ref": "agt_ap", "version": "1.4.0"}})
_, err = client.RedTeam.CreateRun(ctx, map[string]any{"target": map[string]any{"type": "agent", "ref": "agt_ap"}, "engine": "garak", "probes": []string{"promptinject", "dan"}})

Configuration​

Variables d'environnement : EAI_PROMPTFOO_NPX.

Clés de valeurs Helm (deploy/helm/enterprise-ai/values.yaml) : controlPlane.config, controlPlane.secrets.

Sécurité​

  • Une dérogation exige l'approbation d'une autre personne que le demandeur.
  • Tenant déduit de l'identifiant d'accès, jamais du corps ; sécurité au niveau des lignes PostgreSQL sur chaque table de tenant.
  • Chaque mutation et décision de politique écrit un événement d'audit chaîné par hachage (G-11).
  • Les erreurs utilisent l'enveloppe standard avec message_i18n en et fr.

Observabilité​

  • Taux de passage des gates et motifs de blocage.
  • traceparent W3C propagé, X-Request-Id renvoyé, les spans portent eai.tenant_id, eai.project, eai.agent_id, eai.run_id.

Unités FinOps​

  • Les vérifications de gate sont peu coûteuses ; les coûts viennent des runs d'évaluation déclenchés.

Modes de défaillance et résilience​

  • Preuve manquante ou périmée -> passed=false avec motifs (échec fermé).

Adoption autonome​

Les pipelines CI d'un client peuvent n'appeler que l'API de gate.

Tests d'acceptation​

  1. Une promotion en prod sans run de red team renvoie passed=false.
  2. Une dérogation approuvée fait passer la gate et est visible dans l'audit.

Feuille de route d'implémentation