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 :
- 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_SIZEpar exécution. - Déclenchement manuel admin (UI) — la page
/#noraexpose 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 appellePOST /api/cockpit/catalog-sync/syncqui proxe vers le démon. - HTTP direct (scripts opérateur) —
POST /syncsur le serviceakko-catalog-syncà l'intérieur du cluster, corps : 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/tablesest 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_bankingpostgres_oltp_publicsectorpostgres_postgis_esgpostgres_postgis_iotcloudera(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/sourcesqui é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 échantillons —
AKKO_SAMPLE_PERCENT(défaut 5 %) etAKKO_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.