Lección 1 — Cadrer

Le problème et l'architecture

7 min de lectura

Este contenido aún no está traducido. Se muestra la versión original.

Lundi, 9 h 10, ticket DATA-412 : « Le chiffre d'affaires 2025 dans le bot ne correspond pas au reporting financier ». L'enquête prend une demi-journée. Le bot, un LLM branché en direct sur BigQuery, avait additionné sale_price sur tous les statuts, articles annulés et retournés compris. Le SQL était valide, la réponse fluide, le chiffre faux de 30 %.

Ce n'est pas un problème de modèle. C'est un problème de définition : nulle part le système ne disait ce que « chiffre d'affaires » veut dire dans cette entreprise.

Pourquoi le text-to-SQL direct échoue en entreprise

Les bancs d'essai publics (Spider, BIRD) mesurent si le SQL généré renvoie le bon résultat sur un schéma propre, avec une question non ambiguë. En entreprise, trois choses changent :

DifficultéExemple sur thelook_ecommerceConséquence avec un LLM en accès direct
Définitions implicites« CA » exclut annulés et retournéschiffre plausible et faux
Valeurs codéesle Brésil s'écrit Brasil, le rayon femme Womenfiltre vide, résultat nul affiché comme un fait
Pièges de jointureusers.gender (client) et products.department (rayon)deux réponses différentes à « les ventes femmes »
Données sensiblesusers.email, street_addressune question naïve peut les exposer
Coûtevents pèse 384 Mo, un SELECT * répété coûtefacture sans plafond

La parade n'est pas un meilleur prompt. C'est de retirer au modèle les décisions qu'il ne doit pas prendre.

Le mécanisme : le modèle choisit des noms, le code écrit le SQL

sequenceDiagram
  participant U as Utilisateur
  participant A as Agent ADK
  participant C as Compilateur sémantique
  participant G as Garde-fous
  participant B as BigQuery
  U->>A: "Top 5 des marques par marge brute en 2025"
  A->>C: interroger(metriques=[marge_brute], dimensions=[marque], 2025, limite=5)
  C->>C: noms connus ? valeurs exactes ? jointures permises ?
  C->>G: SQL + paramètres
  G->>B: dry-run (gratuit)
  B-->>G: SELECT, 2 tables, 7 Mo
  G->>B: exécution, maximum_bytes_billed = 1 Go
  B-->>A: 5 lignes, 21 Mo facturés
  A-->>U: réponse + barres + limites + 3 questions de suite

Quatre décisions structurent le projet :

  1. Un catalogue fermé. Le modèle reçoit la liste des métriques et des dimensions avec leur définition. Il ne voit ni les tables ni les colonnes. Une colonne absente du catalogue (l'e-mail) n'est pas « interdite » : elle n'existe pas.
  2. Un compilateur déterministe. Même requête métier, même SQL, à l'octet près. Il se teste sans modèle.
  3. Une validation en profondeur. Le compilateur ne produit que des SELECT ; on vérifie quand même par un contrôle statique, puis par le dry-run de BigQuery, puis par un plafond appliqué par BigQuery lui-même.
  4. Le graphique décidé par le code. Le modèle peut suggérer « ligne » ; si le résultat n'a pas d'axe temporel, le code refuse la suggestion.

La mise en œuvre : récupérer le dépôt et vérifier l'outillage

Le dépôt est dans files/. Son organisation suit le flux ci-dessus :

files/
  semantique.yaml        définitions métier : métriques, dimensions, jointures, valeurs
  assistant/
    semantique.py        compilateur YAML -> SQL paramétré
    garde_fous.py        statique, dry-run, liste blanche, plafond, exécution
    graphiques.py        choix du graphique, spec Vega-Lite
    agent.py             agent ADK, outil interroger, sortie structurée
    web.py               API FastAPI + fichiers web/
  web/                   index.html, app.js, style.css
  eval/                  20 questions + SQL de référence + juge
  tests/                 57 tests sans réseau
  infra/                 deployer.sh, nettoyer.sh, statut.sh
  ci/github-actions.yml  à copier dans .github/workflows/

Installez et lancez les tests. Ils n'ont besoin d'aucun identifiant : BigQuery et le modèle sont remplacés par des doublures.

cd files
make setup      # crée .venv, installe requirements.txt, copie .env.example en .env
make test

Résultat obtenu le 2026-10-15 sur un clone neuf :

Prêt. Renseignez .env puis : make test
.........................................................                [100%]
57 passed in 1.96s

Renseignez ensuite GOOGLE_CLOUD_PROJECT dans .env. Le projet sert à payer les requêtes BigQuery et les appels Gemini ; les données, elles, sont publiques et restent dans le projet bigquery-public-data.

Ce qui casse en production

SymptômeCauseParade
make test échoue sur GOOGLE_CLOUD_PROJECT n'est pas définiun test appelle BigQuery pour de vraila cible test retire la variable (env -u) : tout appel réseau échoue bruyamment au lieu de passer en silence sur votre poste
Les chiffres de l'assistant changent d'un jour à l'autrethelook_ecommerce est régénéré quotidiennementnormal ici ; en production, figez une date d'arrêté (snapshot) dans la couche pour les chiffres publiés
Des ventes datées de demainle jeu synthétique contient des horodatages futurs (jusqu'au 2026-10-18 lors de nos mesures)filtre permanent oi.created_at < CURRENT_TIMESTAMP() dans le YAML
Deux équipes, deux chiffresdéfinitions dupliquées dans des tableaux de bordune seule couche, versionnée, relue comme du code

La règle de décision

  • Couche sémantique + agent quand les questions portent sur des indicateurs connus et que l'exactitude engage quelqu'un (comité, client, finance).
  • SQL libre généré seulement pour l'exploration par des analystes qui relisent le SQL avant de croire le chiffre, sur un jeu sans données sensibles.
  • À surveiller dès le premier jour : la part de questions refusées faute de métrique. Elle dit quoi ajouter au catalogue.

Pratique

Un responsable demande « les ventes aux femmes en 2025 ». Le jeu contient users.gender (F/M) et products.department (Women/Men). Que doit faire l'assistant ?

Votre équipe hésite : donner au modèle le schéma complet des 7 tables pour qu'il écrive le SQL, ou un catalogue de 8 métriques et 15 dimensions. Quel argument tranche en faveur du catalogue ?

Exercice. Listez trois questions que votre direction commerciale pose chaque semaine. Pour chacune, écrivez la métrique, la dimension et le filtre qu'elle implique, puis la définition métier qui manque aujourd'hui dans vos outils.

Voir la solution

Exemple sur une boutique en ligne :

QuestionMétriqueDimensionFiltreDéfinition à écrire
« Où en est le CA du mois ? »chiffre_affairesjourmois en coursstatuts inclus ; date de commande ou d'expédition ?
« Quels produits reviennent le plus ? »taux_retourcategorie90 derniers joursdénominateur : articles livrés, pas commandés
« Les nouveaux clients achètent-ils moins ? »panier_moyen(nouveau / existant)trimestre« nouveau » = première commande dans la période ?

La troisième ligne montre une dimension absente du catalogue de ce projet (ancienneté du client) : c'est exactement le type de manque que l'assistant doit signaler au lieu de l'approximer.

  • Je sais expliquer pourquoi un SQL valide peut donner un chiffre faux
  • Je sais situer le compilateur, les garde-fous et le modèle dans le flux d'une question
  • J'ai lancé make setup et make test (57 tests verts sans identifiants)
Siguiente