Aller au contenu

Sentral

En bref

Sentral est le serveur qui sert la connaissance interne de SenSaaS aux agents IA, par MCP et par une API REST. Il combine une recherche hybride dans la documentation et cinq registres déterministes (plan comptable, schéma Sage, rapports, colonnage, base d'assistance Sage). Il tourne sur la tour du bureau et se joint en HTTP, sans identifiant.

Ce que Sentral sert

L'objectif est simple à énoncer : un agent trouve la bonne information sans explorer les dépôts et sans brûler des jetons. On paie une fois à l'ingestion — la structure est pré-calculée — et la lecture devient quasi gratuite.

La recherche documentaire

Sentral découpe chaque document par section (titres de niveau 1 à 4) et préfixe chaque passage de « titre — section », ce qui rend les citations exactes. La recherche fusionne trois signaux : le plein texte français, le titre et la section, et — si la clé d'embeddings est présente — la similarité sémantique. Sans cette clé, Sentral fonctionne en plein texte seul : dégradé, mais utilisable dès le premier jour.

Les cinq registres déterministes

C'est la leçon structurante du projet : un référentiel structuré ne se cherche pas comme de la prose. Avant d'avoir sa table dédiée, la bonne fiche de compte du plan comptable sortait 16ᵉ sur 9 582 passages — les milliers d'exemples d'écritures, tous bâtis sur le même gabarit, la noyaient. Chaque référentiel a donc en plus un registre et son outil : la réponse ne dépend plus d'une similarité, elle est calculée.

Registre Contenu annoncé Outils
Plan comptable général 574 comptes find_account
Schéma Sage 100 402 tables, 3 745 colonnes documentées, 977 énumérations sage_find_table, sage_describe_table, sage_columns, sage_joins
Rapports comptables 5 états confrontés au centime sur deux bases find_report, read_report
Colonnage des listes Sage 59 listes, 2 172 colonnes, 38 tables — toutes valide colonnage_find, colonnage_liste
Base d'assistance Sage France 6 220 articles sage_kb_find, sage_kb_read

S'y ajoutent le contrat de l'API SenSaaS (16 routes) et 7 règles de terrain mesurées sur un vrai Sage.

Les volumes annoncés

État relevé au 2026-09-10 dans les sources du dépôt :

Outils MCP 25
Sources documentaires 10
Documents indexés 1 482
Passages indexés 9 884, tous vectorisés
Dépôts de code indexés 3 dépôts, 125 fichiers, 1 027 symboles
Contrôles 207 tests, sonde de contrats 138/138, banc de coût 37 appels sans dépassement

Ces chiffres sont mesurés, pas promis : un banc de coût relève ce que chaque outil consomme et un test échoue si l'un sort de son budget. Trouver la bonne table Sage, lire sa fiche et cibler trois colonnes coûte environ 850 jetons, pas 10 000.

Ce que le banc de coût a évité

Un plafond n'est pas un budget : une réponse tronquée à 6 000 caractères respecte le plafond tout en coûtant 1 500 jetons pour une question à laquelle trois lignes répondent. C'est arrivé — l'enrichissement du schéma Sage avait fait passer une fiche de table de 684 à 1 139 jetons. La fiche est redevenue un résumé (426 jetons) et les colonnes se demandent à part, filtrées (147 jetons). Personne ne l'aurait vu sans le banc.

S'y connecter

Rien à installer : ni Python, ni base, ni identifiant. Quatre lignes dans le fichier .mcp.json d'un projet suffisent.

{ "mcpServers": {
    "sentral": { "type": "http", "url": "http://debian.lan:8101/mcp" }
}}

Un agent de code demande une fois d'approuver un serveur déclaré par un projet : c'est normal, pas une panne.

Vérifier que le serveur répond :

curl -s -o /dev/null -w '%{http_code}\n' http://debian.lan:8101/mcp

400 est la bonne réponse : le transport MCP attend un POST avec ses en-têtes, pas un GET nu. Un curl: (7) signifie que le serveur ne répond pas — ou que le poste n'est pas sur le réseau du bureau. Si le nom d'hôte ne se résout pas (c'est fréquent sous Windows), l'adresse numérique de secours est dans DEPLOIEMENT.md du dépôt ; le nom reste préférable, l'adresse étant attribuée dynamiquement.

Le fichier .mcp.json du dépôt échouera, et c'est voulu : le serveur n'écoute que sur l'adresse du réseau local du bureau, jamais sur toutes les interfaces. La bonne voie est votre propre instance, sur votre clone :

cd sentral
docker compose up -d                               # PostgreSQL 17 + pgvector, en local
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
cp .env.example .env
.venv/bin/python -m sentral.ingest                 # la documentation
.venv/bin/python -m sentral.index_code             # les symboles de code
claude mcp add sentral -- $PWD/.venv/bin/python -m sentral.mcp_server

Ne pas « dépanner » l'accès à distance en ouvrant le serveur

Faire écouter le serveur sur toutes les interfaces ouvrirait le port à tous les pairs du réseau privé virtuel de l'entreprise, en silence. Le programme de lancement cherche une adresse dans le préfixe du bureau et refuse de démarrer s'il n'en trouve pas : pas de repli. Le refus a été vérifié, pas seulement écrit.

Ce qui marche sans base de données

C'est la bonne surprise du dépôt : les registres lisent des fichiers versionnés. Dès le clone, sans PostgreSQL, sans clé et sans réseau, ces outils répondent :

  • schéma Sage : sage_find_table, sage_describe_table, sage_columns, sage_joins ;
  • base d'assistance Sage : sage_kb_find, sage_kb_read ;
  • colonnage : colonnage_find, colonnage_liste ;
  • rapports comptables : find_report, read_report ;
  • règles de terrain et contrat de l'API : sage_rules.

Exigent PostgreSQL en revanche : search_docs, find_document / read_document, find_symbol / read_symbol, find_endpoint, et find_account — le registre du plan comptable est construit en base depuis le corpus de comptabilité. Le détail outil par outil est sur Les 25 outils de Sentral.

L'API REST

Pour les consommateurs qui ne parlent pas MCP (un backend, une application, un script), Sentral expose aussi une API REST : état du serveur, liste des sources, recherche, lecture d'un document, et les points d'entrée du schéma Sage.

Mettre à jour : le cycle, et son piège

Un git pull met à jour les fichiers, pas les données. C'est l'erreur la plus coûteuse du projet parce qu'elle est silencieuse : un index qui date fait citer juste et renvoyer faux. Au moment du déploiement, 258 symboles sur 1 027 pointaient sur la mauvaise ligne de code.

La séquence complète, sur la machine qui héberge le serveur :

git pull
cd sentral
.venv/bin/python -m sentral.ingest                 # si un corpus ou un document a bougé
.venv/bin/python -m sentral.index_code sentral     # si du code a bougé — jamais optionnel
systemctl --user restart sentral-mcp

Un test vérifie désormais l'alignement des symboles, avec sa contrepartie assumée : la suite de tests passe au rouge après toute modification de code indexé, jusqu'à la réindexation. C'est voulu, mais c'est un péage sur la boucle de développement.

Les registres, eux, suivent le pull immédiatement : ce sont des fichiers.

Le chemin des sources est en dur

Les fichiers de déclaration des sources et des dépôts portent des chemins absolus, qu'aucune variable d'environnement ne remplace. Sur un poste, il faut soit recréer l'arborescence, soit éditer ces fichiers — mais ne jamais commiter ces éditions : elles casseraient l'ingestion du serveur du bureau. Une source dont le chemin est absent est ignorée avec un avertissement et l'ingestion continue : un clone nu produit donc une base partielle mais valide.

Administrer le serveur du bureau

Le serveur tourne comme une unité systemd utilisateur, avec le maintien de session activé : elle démarre au démarrage de la machine sans session ouverte, et n'a demandé aucun privilège d'administration. La base tourne dans un conteneur Docker, exposée sur la boucle locale uniquement.

systemctl --user status sentral-mcp        # état
systemctl --user restart sentral-mcp       # redémarrer
journalctl --user -u sentral-mcp -n 50     # journal

Ce qui n'a pas été essayé

Le démarrage à froid. La machine n'a pas été redémarrée pour vérifier que le service revient seul. Le maintien de session est actif, l'unité est activée, et le refus de démarrer sans adresse du bureau a été vérifié — mais l'enchaînement complet démarrage → réseau → service n'a pas été exécuté.

La démonstration pour l'équipe

Une démonstration est publiée sur le port 8090 de la même machine : cinq agents branchés sur Sentral, avec les appels d'outils affichés, ouverts, avant la réponse. C'est tout le propos — sans cela, c'est un agent conversationnel de plus ; avec cela, on lit d'où vient l'information et on constate quand le modèle raconte autre chose que ce que l'outil a renvoyé.

Capture à venir

Démonstration senkb : cinq agents branchés sur Sentral — identifiant agents/demo-senkb. L'image sera ajoutée lors de la prochaine campagne de captures.

Une seconde page liste les 25 outils, les sources et les mesures, lues en direct sur le serveur : aucun chiffre n'y est recopié à la main.

Ce qui distingue les cinq agents n'est pas le modèle — il est le même pour tous — mais quels outils chacun a le droit d'appeler : de 4 outils pour l'agent tourné client à 25 pour l'agent interne.

Ce que la démonstration a mesuré

questions d'exemple déclenchant au moins un appel d'outil 16 sur 16
l'agent comptable nomme le bon compte 7 fois sur 8
latence par question 10 à 39 s (médiane environ 17 s)

L'exemple qui a décidé de cette maquette : interrogé de mémoire sur « quel compte pour la TVA récupérable sur achats », le modèle répond avec aplomb un numéro faux ; le registre du plan comptable répond le bon. La démonstration ne prouve pas qu'on a un agent conversationnel, elle prouve que la réponse vient du registre, et qu'on le voit.

Limites connues

Elles sont écrites, pas cachées :

  • find_account se trompe sur le vocabulaire courant : 7 bonnes réponses en première position sur 15 questions, et 4 fois sur 15 il sert cinq comptes faux sans dire qu'il n'a rien trouvé. La cause est identifiée — le plan comptable nomme des catégories (« achats de fournitures non stockables »), l'utilisateur nomme une chose (« électricité »). Deux détecteurs ont été essayés et tous deux réfutés. Contournement en place : chercher d'abord dans les articles, qui portent le vocabulaire courant ;
  • la recherche documentaire n'a pas de banc de mesure. C'est la moitié « prose » du serveur et rien ne mesure si ce qu'on y met est effectivement retrouvable. C'est la raison pour laquelle les 6 220 articles Sage sont servis par un registre et non par la recherche ;
  • l'ingestion est manuelle : pas encore de synchronisation automatique ;
  • les quatre dépôts produit ne sont pas indexés, faute d'un jeton d'accès en lecture au dépôt de sources. C'est le plus gros gain immédiat encore disponible ;
  • aucun droit par outil. Voir Règles pour les agents.

Questions fréquentes

Faut-il un mot de passe pour appeler Sentral ?

Non. Le réseau est l'authentification : le serveur n'écoute que sur l'adresse du réseau local du bureau. Le jour où un accès depuis l'extérieur sera nécessaire, il faudra un délivreur de jetons ; c'est une phase à part, cadrée mais non réalisée.

Sentral lit-il des données clients ?

Non. Le dépôt ne contient aucune donnée client réelle : seules des fiches lavées, bases sous alias. L'API vivante, elle, est servie par un autre serveur — voir MCP du connecteur.

Pourquoi ma suite de tests passe-t-elle au rouge après un simple git pull ?

Parce que l'index de symboles ne suit pas les fichiers. Relancez index_code, puis redémarrez le service. Voir « Mettre à jour » ci-dessus.

Voir aussi