Aller au contenu

Auto-enrichissement du catalogue avec NORA

TL;DR

NORA est la file de revue steward pour les enrichissements catalogue proposés par l'IA. Le Service d'auto-enrichissement du catalogue échantillonne quelques lignes de chaque source fédérée (bases opérationnelles, tables lakehouse, etc.), demande au LLM on-prem de proposer une description + des étiquettes PII + des candidats clés étrangères, et écrit ces propositions dans une file Postgres. Les stewards les revoient depuis la page /#nora du cockpit, puis acceptent / éditent / rejettent.

Les propositions acceptées sont écrites en retour dans la couche Catalog (OpenMetadata) et immédiatement injectées dans le store vectoriel (Milvus) afin que le moteur ADEN (langage naturel → SQL) les reflète en quelques millisecondes.

Aucun échantillon de ligne ne quitte le cluster.


Cartographie des couches

Couche (utilisateur) Moteur (admin)
Catalog OpenMetadata
Service d'auto-enrichissement du catalogue démon akko-catalog-sync
Passerelle IA LiteLLM
Store vectoriel Milvus
File de revue steward Postgres catalog_sync.proposals_pending
Page revue cockpit /#nora

Les noms d'éditeurs n'apparaissent qu'ici dans la doc Architecture / Ops et jamais dans les surfaces utilisateur (sidebar, KPI, toasts).


Flux de bout en bout

flowchart LR
    A[Source fédérée<br/>postgres_oltp_banking, iceberg, cloudera, climscore, …] -->|TABLESAMPLE| B[Service d'auto-enrichissement]
    B -->|prompt| C[Passerelle IA]
    C -->|description<br/>+ étiquettes PII<br/>+ candidats FK| B
    B -->|insert| D[File de revue<br/>proposals_pending]
    D --> E[Cockpit /#nora]
    E -->|accepter| F[Catalog]
    E -->|accepter| G[Store vectoriel]
    F --> H[ADEN NL→SQL]
    G --> H

Déclencheurs

Le service a 3 points d'entrée :

  1. CronJob (par défaut) — s'exécute toutes les 6 h, balaye les tables modifiées depuis le dernier watermark. Peut rester actif en permanence ; le coût LLM est borné par AKKO_SYNC_BATCH_SIZE par exécution.
  2. Déclenchement manuel admin (UI) — la page /#nora expose une carte Déclencher l'enrichissement catalogue réservée admin. L'admin sélectionne une source fédérée depuis la datalist (alimentée en direct par /api/catalogs/sources), limite facultativement le nombre de tables, coche éventuellement mode test, et clique sur Lancer l'enrichissement. Le cockpit appelle POST /api/cockpit/catalog-sync/sync qui proxe vers le démon.
  3. HTTP direct (scripts opérateur) — POST /sync sur le service akko-catalog-sync à l'intérieur du cluster, corps :
    { "source": "postgres_oltp_banking", "limit": 50, "dry_run": false }
    
    Voir API HTTP ci-dessous pour le schéma complet.

API HTTP

POST /sync sur akko-catalog-sync:8000

Champ Type Défaut Description
source string|null null Nom de catalogue Trino / service OM. Résout en préfixe FQN <source>.. Exclusif avec fqns.
fqns string[]|null null Liste explicite de noms qualifiés de tables. L'emporte sur source.
since_ms int 0 Watermark incrémentale (ms Unix). 0 = scan complet dans le périmètre.
limit int 50 Nombre max de tables traitées dans cette exécution (1–500).
dry_run bool|null défaut env Si true, aucune écriture vers Catalog ou store vectoriel.

Réponse : 200 avec un tableau de résultats par table, chacun contenant fqn, description, confidence, pii_columns, om_updated, milvus_upserted, error.

Réponses d'erreur :

  • 404 no tables matched the request — le listing OM /tables est vide pour cette source. Signifie généralement que l'ingestion OM n'a pas encore tourné (voir Prérequis ci-dessous).
  • 404 no OpenMetadata tables matched source='<x>' — le nom de source diffère du serviceFQN OM. Vérifier dans Catalog Manager.
  • 401 / 403 — appelant sans rôle admin (la gate admin est appliquée en amont par le oauth2-proxy du cockpit).

Prérequis

Avant que NORA puisse produire des propositions pour une source, la source doit être indexée dans OpenMetadata. C'est un setup unique par source :

# 1. Enregistrer le service base dans OpenMetadata
#    (OM UI → Settings → Database Services → Add)
# 2. Lancer un workflow d'ingestion de métadonnées
#    (OM UI → Ingestions → Run, ou DAG Airflow akko_om_ingestion)
# 3. Confirmer que les tables apparaissent dans /api/catalogs/search?q=*

Une fois l'ingestion ayant peuplé table_search_index, l'endpoint /api/catalogs/sources listera la source et la datalist de la carte de déclenchement la proposera en suggestion.

La mission Sprint 82 A4 a documenté les 6 sources cibles :

  • postgres_oltp_banking
  • postgres_oltp_publicsector
  • postgres_postgis_esg
  • postgres_postgis_iot
  • cloudera (livrée par Sprint 82 A2)
  • climscore (livrée par Sprint 82 A3, fédération lecture-seule)

Matrice RBAC

Persona Sidebar /#nora Carte déclenchement Accepter / Rejeter Mode test uniquement
alice (admin) oui oui oui oui
dave (steward) oui non oui non
bob (engineer) non non non non
carol (analyst) non non non non
eve (viewer) non non non non

La surface de déclenchement admin est volontairement cachée aux stewards : les stewards revoient, les admins opèrent. Un steward qui a besoin d'un nouveau batch contacte un admin ou attend le CronJob 6 h.


Runbook opérationnel

Symptôme Cause probable Correction
Déclencheur renvoie 404 "no tables matched" Ingestion OM non lancée pour cette source Enregistrer le service + lancer le workflow d'ingestion
Déclencheur renvoie 404 "source name differs" Faute de frappe, ou service OM nommé autrement que le catalogue Trino Vérifier /api/catalogs/sources, utiliser le name exact
Carte cachée pour un admin Claim de token caché pré-déploiement Rafraîchissement hard + re-connexion
Datalist vide /api/catalogs/sources a renvoyé [] ou 5xx Vérifier la santé OM + logs cockpit-backend
Compteur pending qui ne monte pas après déclenchement Démon a renvoyé 200 mais avec error par ligne Inspecter logs démon : échec sampler / LLM / sink
Proposition acceptée non visible dans OM PATCH OM best-effort fire-and-forget en échec Re-déclencher l'accept (idempotent)
ADEN renvoie toujours l'ancienne description Course Milvus upsert vs lecture Attendre 1 s, retenter — la consistance éventuelle est typiquement sub-seconde

Notes de discipline

  • Zéro source en dur — la datalist cockpit est alimentée par /api/catalogs/sources qui énumère les services base OM. Ajouter une nouvelle source = l'enregistrer dans OM et lancer l'ingestion ; aucun changement de code requis.
  • Vocabulaire couche-d'abord — chaque label visible utilisateur parle d'« Auto-enrichissement du catalogue », « Source fédérée », « Table lakehouse », « Base opérationnelle ». Les noms d'éditeurs vivent uniquement dans cette doc admin.
  • Aucun bypass SSH — chaque action opérateur passe par cockpit oauth2-proxy → cockpit-backend → démon. Le démon n'expose jamais d'Ingress public.
  • Conscient des échantillonsAKKO_SAMPLE_PERCENT (défaut 5 %) et AKKO_DESCRIPTION_MAX_WORDS (défaut 100) bornent à la fois la taille de l'échantillon et la sortie LLM, donc aucun snapshot de table complet ne quitte le cluster et les descriptions ne gonflent pas démesurément.