Documentation technique du prototype

Comment fonctionne l’agent d’exploration ?

Cette page décrit l’implémentation actuelle : orchestration AI SDK, outils, données échangées, visualisations, feedback et garde-fous. Elle documente un prototype, pas une architecture cible définitive.

Orchestration

Architecture et cycle d’une réponse

Le serveur appelle le modèle ; le fichier Parquet, DuckDB et les outils de données restent dans le navigateur.

  1. 1. Charger

    Le navigateur télécharge la ressource Parquet, initialise DuckDB-WASM et conserve son schéma en mémoire.

  2. 2. Planifier

    Le modèle interprète la demande, décide s’il faut clarifier et choisit les outils nécessaires.

  3. 3. Exécuter

    Les tools serveur ou navigateur produisent des preuves structurées, puis leurs sorties sont réinjectées dans la conversation.

  4. 4. Poursuivre

    AI SDK relance automatiquement l’agent après un tool local, dans une limite globale de cinq étapes.

  5. 5. Restituer

    Le modèle rédige une réponse concise et peut demander une visualisation ou proposer une vue de l’explorateur.

La page Vue utilise useChat et DefaultChatTransport. La route Nitro appelle streamText. Après chaque tool local, sa sortie est ajoutée au message et AI SDK relance automatiquement l’agent.

Au chargement de la page, une route dédiée lit en parallèle les métadonnées publiques du jeu de données pour construire sa fiche de contexte. Cette présentation reste indépendante du moteur DuckDB, de l’explorateur et du panneau assistant. Les deux recherches de l’explorateur utilisent une primitive visuelle commune afin d’éviter leur divergence.

La boucle est bornée par isStepCount(5). Une réponse complexe doit donc partager ces cinq étapes entre inspections, corrections SQL, visualisation et réponse finale.

L’interface dérive quatre phases observables des messages AI SDK : planification avant le premier tool, utilisation des tools pendant leurs appels, interprétation après leurs sorties et rédaction dès que le texte final commence à arriver. Un identifiant de message assistant actif garantit qu’un seul état de progression est affiché. Une temporisation de 700 ms absorbe les passages transitoires à ready entre une sortie locale et la reprise automatique suivante.

Le raisonnement visible est une synthèse déterministe des actions observables : intention comprise, contexte consulté, nombre de calculs, colonnes du résultat et représentation choisie. Il n’expose pas la chaîne de pensée privée du modèle. Les formulations descriptives des tools sont demandées en français et écartées de cette synthèse lorsqu’elles semblent être en anglais. Les traces techniques restent séparées dans « Outils utilisés ».

Les erreurs de tool restent transitoires tant que le statut global est submitted ou streaming. Une erreur remplacée par une sortie réussie ultérieure du même tool est retirée à la fois des traces et de la zone de visualisation finale.

Génération

Fournisseur et modèle

Le choix du fournisseur est réalisé côté serveur, sans exposer de clé au navigateur.

Priorité 1
Vercel AI Gateway avec clé explicite
Priorité 2
Endpoint OpenAI-compatible, dont Albert
Priorité 3
Jeton OIDC fourni par Vercel
Modèle Gateway par défaut
openai/gpt-5.4-mini

Les variables historiques ALBERT_API_URL, ALBERT_API_KEY et ALBERT_MODEL sont reconnues pour faciliter les déploiements existants.

La puce visible dans l’interface affiche encore gpt-oss-120b de manière statique. Elle devra être reliée à la configuration effective pour éviter une divergence entre interface et backend.

Capacités

Outils disponibles

Le modèle choisit un tool, mais son contrat Zod et son exécution restent sous le contrôle de l’application.

request_clarification

Interface + utilisateur
Entrée :
Question courte et deux à quatre choix distincts.
Sortie :
Choix explicite de l’utilisateur.
Implémentation :
Suspend l’analyse, affiche les choix sous forme de suggestions cliquables, puis reprend automatiquement avec la précision retenue.

get_dataset_metadata

Serveur
Entrée :
Contexte du jeu de données actif.
Sortie :
Titre, description, producteur, licence, qualité, dates et ressources.
Implémentation :
Interroge l’API publique data.gouv.fr. Il ne lit pas les valeurs de la ressource.

inspect_schema

Navigateur
Entrée :
Table DuckDB locale data.
Sortie :
Nombre de lignes, colonnes, types et échantillon.
Implémentation :
Utilise DuckDB-WASM et réutilise le schéma chargé au démarrage.

execute_sql

Navigateur
Entrée :
Requête DuckDB et objectif explicite.
Sortie :
Colonnes, 100 premières lignes, troncature et durée.
Implémentation :
Valide puis exécute une unique requête SELECT ou WITH en lecture seule.

propose_explorer_view

Navigateur + utilisateur
Entrée :
Requête en lecture seule, titre et justification.
Sortie :
Vue appliquée, colonnes, nombre de lignes et troncature.
Implémentation :
Prévisualise et vérifie la requête, puis affiche une confirmation. La vue ne remplace le tableau qu’après un clic utilisateur.

create_chart

Navigateur
Entrée :
Type, titre, axe et jusqu’à quatre séries.
Sortie :
Jusqu’à 1 000 lignes provenant du dernier SQL vérifié.
Implémentation :
Contrôle les champs demandés puis réalise le rendu avec ECharts.

create_map

Navigateur
Entrée :
Spécification points, GeoJSON ou choroplèthe.
Sortie :
Jusqu’à 5 000 lignes provenant du dernier SQL vérifié.
Implémentation :
Contrôle les champs puis réalise le rendu avec MapLibre et les contours administratifs nécessaires.

Garde-fous

Exécution, données transmises et sécurité

Le prototype sépare le calcul local, l’orchestration serveur et le rendu de l’interface.

Dans le navigateur

  • Ressource Parquet et instance DuckDB-WASM.
  • Schéma, requêtes SQL et résultats bornés.
  • Tableau, console SQL, ECharts et MapLibre.
  • Historique courant de la conversation.

Envoyé au modèle

  • Question et historique de la conversation.
  • Contexte de la ressource et schéma chargé.
  • Appels d’outils et sorties nécessaires.
  • Erreurs SQL utiles à une éventuelle correction.

Le validateur SQL accepte une seule requête commençant par SELECT ou WITH. Il refuse notamment INSERT, UPDATE, DELETE, DROP, ALTER, CREATE, COPY, ATTACH, INSTALL, LOAD, CALL et PRAGMA.

Une requête doit avoir été exécutée avec succès avant de pouvoir être appliquée à l’explorateur ou utilisée comme source d’une visualisation. Le prompt demande au modèle de ne pas dépasser trois essais SQL par question ; la route serveur impose aussi ce plafond en retirant réellement execute_sql des tools disponibles une fois le budget consommé.

Les métadonnées, noms de colonnes, valeurs, échantillons et sorties de tools sont explicitement traités comme des données non fiables. Le contexte actif est sérialisé dans un bloc délimité afin qu’une instruction malveillante contenue dans une ressource ne soit pas confondue avec une instruction système.

Les erreurs finales passent par une classification commune : réseau et fournisseur proposent de régénérer le message concerné ; SQL et visualisation rendent le focus au compositeur pour préciser la demande ; DuckDB propose de recharger la ressource. Le message principal est volontairement non technique. Le texte d’origine reste accessible dans un élément details replié par défaut.

Rendu

Graphiques et cartes

Les visualisations sont toujours construites à partir du dernier résultat SQL vérifié.

Graphiques : ECharts prend en charge barres, courbes, aires, secteurs et nuages de points, avec jusqu’à quatre séries et 1 000 lignes.

Cartes : MapLibre prend en charge des coordonnées, une géométrie GeoJSON ou une jointure par région ou département français, dans une limite de 5 000 lignes. Les libellés privilégient le français ; les styles officiels de openmaptiles.geo.data.gouv.fr fournissent OSM Bright par défaut et Positron pour les choroplèthes.

Avant le rendu, un nom de colonne manquant n’est remplacé que si un alias unique correspond au rôle attendu et aux valeurs observées. Une ambiguïté interrompt la création. La carte signale les coordonnées invalides et les territoires non appariés ; à partir de 100 points, les lieux proches sont regroupés selon le niveau de zoom.

Les champs demandés par la spécification sont comparés aux colonnes du résultat SQL. Une visualisation est refusée si un champ manque. Le loader conserve la taille du composant final et reste visible au moins 900 ms.

Amélioration continue

Mécanisme de feedback

Chaque réponse peut recevoir une évaluation utile ou inutile, complétée si nécessaire par un commentaire.

  1. L’utilisateur choisit un pouce sous une réponse. Un tooltip précise les données transmises.
  2. La route serveur valide le contenu avec Zod, vérifie l’origine de la requête et enregistre immédiatement l’évaluation dans Grist. L’origine fonctionnelle est conservée dans le champ de détails existant.
  3. Quand ils sont disponibles, le nom du jeu de données, son URL data.gouv.fr et le nom de la ressource sont enregistrés dans Dataset_name, Dataset_url et Ressource_name.
  4. Après l’envoi, l’interface propose d’ouvrir un formulaire Grist prérempli avec la question, la réponse, la ressource, le jeu de données, le modèle et la date.
  5. Après six questions, une invitation unique propose également ce formulaire et préfixe la question avec « Invitation après 6 questions ».
  6. L’interface indique le succès ou permet de réessayer en cas d’échec.

Le prototype n’envoie pas d’identité, mais le texte de la question et de la réponse fait partie du retour. Le formulaire détaillé reste facultatif.

Instructions

Organisation des prompts

Les instructions sont découpées par responsabilité afin de rester lisibles, testables et portables.

Les deux suggestions contextuelles de l’empty state ne sollicitent pas le modèle : une fonction déterministe inspecte les noms et types DuckDB du schéma déjà chargé. Cela rend leur apparition immédiate, reproductible et sans coût de tokens.

Une politique dédiée demande un tableau Markdown pour les classements, distributions, comparaisons, listes de colonnes et exemples structurés, mais l’écarte pour une valeur unique ou une explication narrative. Elle limite les résultats à 10 lignes par défaut et 20 sur demande explicite ; les résultats plus longs sont orientés vers l’explorateur. Cette limite porte sur les lignes de données, pas sur le nombre de colonnes : toutes les colonnes nécessaires à la compréhension et à la vérification doivent être conservées.

Les questions demandant simplement la liste des colonnes sont traitées sans appel au modèle : le serveur construit directement un tableau Markdown exhaustif depuis le schéma chargé et traduit les types DuckDB. Cette liste n’est plus tronquée à 20 colonnes. Le renderer stabilise les débuts de tableaux incomplets pendant le streaming, les enveloppe dans un conteneur horizontal, leur donne au minimum toute la largeur disponible et maintient un espacement lisible avec le paragraphe suivant.

Identité et preuves

Définit le rôle de l’assistant, la table locale et l’interdiction de répondre sans résultat attesté.

server/agents/prompts/identity.ts

Périmètre

Réévalue chaque message, refuse les demandes hors sujet et distingue une capacité pertinente mais indisponible.

server/agents/prompts/scope.ts

Données non fiables

Empêche les métadonnées, colonnes, valeurs et sorties de tools d’être interprétées comme des instructions.

server/agents/prompts/untrusted-data.ts

Économie et limites des preuves

Réutilise les preuves existantes et encadre l’interprétation des échantillons, top-N, limites et ex æquo.

server/agents/prompts/evidence.ts

Planification et clarification

Choisit la preuve la plus légère et demande une précision lorsque plusieurs interprétations changeraient le résultat.

server/agents/prompts/routing.ts

Politique SQL

Encadre les colonnes, les correspondances exactes, les agrégations, les limites et la correction des requêtes.

server/agents/prompts/sql.ts

Politique de l’explorateur

Distingue une réponse conversationnelle d’une demande explicite de modification du tableau.

server/agents/prompts/explorer.ts

Politique des visualisations

Détermine quand et comment créer un graphique ou une carte à partir d’un SQL réussi.

server/agents/prompts/visualizations.ts

Politique de réponse

Impose le français, une réponse directe, des limites visibles et l’absence de jargon interne.

server/agents/prompts/response.ts

À chaque requête, ces couches sont assemblées avec le contexte actif : titre, producteur, références, ressource et schéma déjà chargé. Le périmètre est réévalué sur le dernier message à chaque tour. Une demande hors sujet reçoit un refus bref sans tool ; une demande pertinente mais non prise en charge reçoit une explication de la limite et une alternative disponible. Les contenus complets restent versionnés dans les fichiers indiqués plutôt que publiés automatiquement par une route publique.

État du prototype

Limites connues et travaux à poursuivre

Ces éléments doivent être pris en compte pendant une démonstration ou un test utilisateur.

  • La recherche dépend de la disponibilité de l’API publique data.gouv.fr et ne retourne que les jeux disposant d’une version Parquet.
  • La conversation et les résultats ne sont pas persistés.
  • La limite de cinq étapes peut être courte après plusieurs corrections SQL.
  • Le libellé du modèle dans l’interface n’est pas encore dynamique.
  • Les erreurs fournisseur restent volontairement simplifiées pour l’utilisateur.
  • Il n’existe pas encore de protocole d’évaluation automatique des réponses.
  • L’assistant de publication et les intégrations futures data.gouv.fr ne sont pas encore implémentés.