Les règles sont publiées avant
les chiffres.
Telys est en version 0.1.0b4 — ces chiffres sont validés sur prototype sur un rig déclaré, non en production. Un résultat n'est valide que s'il est mesuré sous recall identique sur matériel identique, avec les échantillons bruts et le script qui les a produits. Les règles ci-dessous s'appliquent à chaque chiffre : ce que nous mesurons, face à qui, et les cas où nous sommes tenus de perdre.
Des règles que le banc d'essai applique, non des réserves que nous ajoutons.
Chaque règle ci-dessous est encodée comme vérification automatique dans le banc d'essai. Une exécution qui la viole n'est pas mise en note — elle est marquée invalide et exclue de tous les tableaux de bord.
“Tout multiplicateur est une hypothèse tant qu'il n'a pas été mesuré sous recall identique et matériel identique, avec les échantillons bruts et un script de reproduction publié.”
Doctrine de benchmark TelysUn benchmark qu'on ne peut pas perdre ne vaut rien
Le tableau de bord généré comporte une section obligatoire Où nous perdons, alimentée automatiquement par chaque cellule remportée par un comparateur. Si cette section est vide, la génération du rapport échoue — un sans-faute est traité comme un banc d'essai défaillant, non comme un triomphe.
Embarqué contre embarqué, c'est le duel équitable
Nous ne mettons jamais en avant un appel en cours de processus face à un concurrent répondant via TCP. Pour les bibliothèques embarquées, in-process contre in-process est le transport honnête. Pour les serveurs, le transport est mis en correspondance à l'identique, ou le chiffre est annoté et exclu des titres.
Niveaux identiques, ou pas de comparaison
Une exécution en mémoire n'est jamais comparée à un concurrent qui fsync chaque commit. Chaque résultat déclare son niveau de durabilité — in_mem, wal_async ou wal_fsync — et le banc d'essai rejette toute comparaison entre niveaux différents.
Nous n'affirmons jamais battre FAISS quand nous appelons FAISS
FAISS est le cœur ANN qu'embarque Telys — un socle, non un adversaire. Chaque tableau de bord vectoriel affiche en premier la cellule de traversée FAISS brut ; en cas d'égalité, l'égalité est affichée. Les victoires honnêtes sont revendiquées ailleurs : noyaux de reranking, planification filtrée et le moteur autour de l'index.
Chaque comparateur isole une affirmation.
Un seul chiffre de classement mélange algorithme, transport, durabilité et format de stockage. L'ensemble est choisi pour que chaque comparaison isole exactement une variable — avec un contrôle sur le même nœud sous chaque titre.
| Système | Forme | Ce que la comparaison isole |
|---|---|---|
| FAISS (même nœud) | Référence de contrôle | Le plancher, non un adversaire. Telys embarque FAISS, donc le chiffre FAISS brut est la référence que nous sommes ; le delta publié est ce que le moteur y ajoute — à la même chaîne d'index et au même recall mesuré. |
| Postgres + pgvector | Relationnel + vectoriel | La requête hybride filtrée : si pousser un prédicat scalaire dans le chemin candidat surpasse un index devant sur-récupérer ou post-filtrer, à recall égal selon les sélectivités de filtre. |
| LanceDB / Chroma | Bibliothèque embarquée | Les concurrents les plus proches, in-process contre in-process — le seul cas où un chiffre in-process constitue un titre équitable. Même plancher ANN ; la comparaison isole le moteur autour de lui : espace d'identifiants de lignes unifié, cold-open, empreinte mémoire. |
| Qdrant / Milvus | Serveur | Qualité algorithmique — recall à k fixe — séparée des allers-retours réseau. La latence est reportée avec le saut serveur annoté et n'est jamais mise en avant face à un appel in-process. |
| Pinecone | Service géré | Recall à k fixe et débit par unité de calcul. La latence brute face à un moteur embarqué est refusée comme indicateur principal ; le contrôle sur le même nœud porte la revendication de qualité à sa place. |
| DuckDB / ClickHouse | Moteur analytique | Scan et agrégation sur le même fichier Parquet physique, afin de dissocier l'avantage du format de stockage de celui du moteur. Les moteurs analytiques vectorisés excellent ici ; leurs victoires sont publiées. |
Ce qui est mesuré.
La matrice définit des mesures, non des victoires hypothétiques. Chaque cellule de latence rapporte la distribution complète — jamais seulement la moyenne — sous charge offerte en boucle ouverte. Chaque cellule de débit est liée à un seuil de recall calculé par le harnais sur la vérité terrain livrée ; une cellule dont le seuil n'est pas atteint est émise invalide et ne peut figurer dans un tableau de bord.
| Charge | Configuration | Ce qu'elle mesure |
|---|---|---|
| cold-open | Cache de pages vidé, démarrage de processus à froid | Temps du démarrage du processus à la première requête réussie — mmap des segments et mapping des index-sidecars face au démarrage serveur et à la récupération. Mesuré séparément de l'état stable, jamais fusionné avec lui. |
| exact FLAT | Recherche exacte par force brute, f32 et int8 | Le plancher du noyau de distance à recall 1.0 par construction, face à la référence exacte sur le même nœud et les mêmes tampons. Chaque cellule int8 rapporte son delta de recall par rapport au f32, de sorte que la perte due à la quantification n'est jamais dissimulée. |
| hybride filtré | Prédicat scalaire + top-k, balayé sur trois sélectivités | Latence à recall égal à mesure que le filtre se resserre, plus la stratégie choisie par le planificateur par cellule — pré-filtre puis exact, pré-filtre puis IVF, ou recherche puis post-filtre — afin que la décision adaptative soit auditable. |
| full scan | Scan et agrégation colonne entière | Débit colonnaire brut sur Parquet partagé, moteur contre moteur sur des octets identiques. |
| analyse sélective | Scan par prédicat à faibles taux de correspondance | Vérification que l'élagage par min-max de pied de page et zone-map saute effectivement du travail — rapporté en octets lus et lignes touchées, pas seulement en temps réel. |
python -m bench.orchestrator.run \
--suite vector --rig m-laptop
# one command: pinned comparators, content-addressed
# datasets, warmup, steady-state measurement
# reviewer mode: the same run with Telys excluded# every run emits a machine-checked ResultEnvelope; # a run that cannot fill every field is invalid index_string = "IVF4096,PQ16" # same for Telys and the FAISS control omp_num_threads = 8 # FAISS threading pinned, disclosed transport = "in_process" # headlined only vs in-process durability_tier = "wal_fsync" # cross-tier comparison hard-fails recall_at_k = 1.000 # harness-measured, never self-reported samples_path = "bench/results/filtered_impact.txt"
Les exécutions se répètent au moins cinq fois sur des démarrages de processus à froid, sur des profils matériels épinglés, un système à la fois. Les jeux de données sont adressés par contenu ; les jeux de requêtes sont des fichiers figés, non générés à l'exécution. La spécification du harnais est validée aujourd'hui ; le harnais est publié avec les résultats.
Mesurés, conditionnés, reproductibles.
Chaque ligne est une vraie exécution sur le rig nommé ci-dessus, au seuil de recall indiqué à côté. La surface de gain est l'organisation physique : sur un sous-ensemble contigu identique, notre scan Mojo égale FAISS brut — le delta ci-dessous est ce qu'apporte l'organisation partitionnée par clé, non un noyau de distance plus rapide. Ce sont des chiffres de prototype, réexécutés sous le contrat d'équité complet à mesure que le harnais mûrit.
| Charge de travail | Configuration + seuil de recall | Résultat mesuré (M4 Max, mono-thread, in-process) |
|---|---|---|
| Slice filtrée · sél. 0,1 % | N=1 000 000 D=128 K=10, warm, recall 1,000 (exact) | partition-slice p50 0,013 ms — gain layout vs scan complet ~373×, vs scatter-gather ~19×. FAISS Flat sur le sous-ensemble identique : 0,040 ms (égalité — prouve que le gain est l'organisation, non le noyau). |
| Slice filtrée · sél. 0,4 % | N=1 000 000 D=128 K=10, warm, recall 1,000 (exact) | p50 0,032 ms — ~128× vs scan complet, ~10,8× vs scatter-gather. Contrôle FAISS Flat 0,035 ms (égalité). |
| Slice filtrée · sél. 1,6 % | N=1 000 000 D=128 K=10, warm, recall 1,000 (exact) | p50 0,112 ms — ~42× vs scan complet, ~10,3× vs scatter-gather. Contrôle FAISS Flat 0,120 ms (égalité). |
| Sauvetage de grande partition | 247 k lignes dans N=400 000 D=128, nprobe calibré, recall 0,9915 (plancher 0,98) | L'IVF intra-partition restaure le gain layout là où un scan exact dégrade : slice exacte 1,71 ms → IVF 0,033 ms. Sans IVF, une seule grande partition ne tient qu'à ~4–5×. |
| Auto-nprobe gouverné | N=1 000 000 D=128 Q=500 nlist=1000, recall maintenu à 0,998 (plancher 0,98) | FIND 0,28–0,31 ms au nprobe de référence=32 → 0,081–0,088 ms avec auto-nprobe gouverné=8. Le recall reste au-dessus du plancher — aucun échange silencieux recall/vitesse. |
| FIND vs contrôle FAISS | Iso-recall, même transport, tous deux in-process, N=1 000 000 D=128 | Telys 0,073–0,074 ms @0,998 vs FAISS brut 0,080 ms @0,999 — parité à légèrement en avance. Dépendant de l'échelle : en retrait (0,74×) à N=200 k, jusqu'à ~1,6× seulement aux grands N memory-bound. Qualité FAISS, accéléré Mojo. |
| Concurrence sans GIL | N=200 000 D=128, 12 cœurs perf, noyau Mojo IVF in-process | Le débit FIND évolue ×6,9 sur 8 threads (15 128 → 104 756 qps). Mise à l'échelle du débit, non de la latence par requête ; non comparé aux moteurs serveur. |
| Fraîcheur insert-to-recall | Base N=100 000, M=300 insertions, D=128, in-process | Un vecteur tout juste inséré est top-1 dès la requête suivante : recall@1-of-new = 1,000. Insert p50 0,3 µs. Seuil de correction, non une performance de débit. |
Chaque cellule ci-dessus est traçable jusqu'à un script nommé et une sortie brute sauvegardée dans bench/results/ (filtered_impact.txt, partitioned.txt, partition_acceptance.txt, opt.txt, telys.txt, concurrency.txt, freshness.txt). Le chiffre de réouverture en persistance est retenu en attente d'un échantillon brut re-mesuré. Tout multiplicateur est une hypothèse en dehors des conditions indiquées dans chaque ligne.
Conçu pour le code — et évalué sur un benchmark code.
Telys récupère du code, donc la référence qualité est CoIR, non une suite texte généraliste. LexicalCodeIndex est encapsulé comme un mteb SearchProtocol et évalué par mteb.evaluate sur le même chemin que les références bm25s — aucun écart méthodologique, aucune auto-évaluation. Les références sont des exécutions reproductibles du 2026-07-21, non les chiffres publiés dans l'article CoIR (plusieurs ne se reproduisent pas). Métrique : nDCG@10.
| Tâche CoIR | multigram | bm25-ref | bm25-code | code-lexical · livré | vs meilleure référence |
|---|---|---|---|---|---|
| CodeTransOceanContest | 0.160 | 0.478 | 0.600 | 0.718 | ✅ |
| CodeTransOceanDL | 0.340 | 0.344 | 0.351 | 0.366 | ✅ |
| CosQA | 0.048 | 0.188 | 0.213 | 0.218 | ✅ |
| SyntheticText2SQL | 0.265 | 0.249 | 0.372 | 0.441 | ✅ |
| CodeFeedbackMT | 0.288 | 0.592 | 0.591 | 0.674 | ✅ |
| CodeFeedbackST | 0.162 | 0.682 | 0.682 | 0.722 | ✅ |
| StackOverflowQA | 0.223 | 0.703 | 0.687 | 0.733 | ✅ |
| AppsRetrieval | 0.001 | 0.048 | 0.014 | 0.034 | ❌ |
| Moyenne | 0.186 | 0.445 † | 0.488 | 7/8 | |
Sept victoires sur huit ; moyenne 0.488 contre 0.445 pour la meilleure référence de chaque tâche († meilleur de bm25-ref / bm25-code, par tâche) — et 2,6× la moyenne multigram. La seule défaite, AppsRetrieval, est proche de zéro pour toute méthode lexicale : des énoncés longs face à du code relève du domaine des embeddings.
Tokens code + BM25
Les identifiants sont découpés selon les conventions du code — camelCase, snake_case, chemins pointés — alimentant un IDF/BM25 standard. Cela seul remporte la plupart des tâches : CodeTransOceanContest passe de 0.478 à 0.600 sans aucun réglage.
Mots vides supprimés, racinisation légère
Mots vides anglais supprimés et raciniseur de suffixes léger pour aligner les requêtes en langage naturel avec les tokens du code — le levier qui fait basculer SyntheticText2SQL d'une défaite à 0.441.
k1 = 1,8 · b = 1,0
Les valeurs par défaut livrées, ajustées par Algenta sur CoIR : saturation de fréquence de terme plus forte et normalisation de longueur complète — le levier qui fait basculer StackOverflowQA.
Chaque cellule se reproduit à partir d'un seul script — bench/mteb_code_lexical.py — faisant passer les deux côtés par le même appel mteb.evaluate (exécutions du 2026-07-21). code-lexical est l'index que Telys livre, avec ses valeurs par défaut.
Victoires, égalités et défaites — par écrit.
Le format de publication est fixé avant que le premier chiffre existe, de sorte que les chiffres ne peuvent pas l'infléchir.
Là où nous perdons, noir sur blanc
Chaque tableau de bord comporte une section Là-où-nous-perdons et une section Là-où-nous-égalons-seulement-FAISS, toutes deux alimentées automatiquement depuis les cellules. Le rapport échoue à la compilation si l'une ou l'autre est vide.
Reproduire les résultats sans nous
Le harnais s'exécute avec Telys exclu, afin qu'un sceptique puisse reproduire seul les chiffres des comparateurs et du contrôle, et confirmer que chaque concurrent a été réglé selon son propre guide — configurations validées et différenciées par rapport aux valeurs par défaut du fournisseur.
Chaque cellule est tracée jusqu'aux échantillons
Chaque cellule publiée renvoie à ses échantillons bruts par opération et au script exact qui les a produits. Les résultats sont en ajout seul, indexés sur la révision du moteur et les versions des dépendances liées statiquement.
Ce sont des chiffres de prototype, chacun accompagné de ses conditions. Tenez-nous à ce contrat — et aux chiffres à mesure que nous les réexécutons sous le harnais complet.