Back to flin
flin

Recherche sémantique et stockage vectoriel

Comment le type semantic text de FLIN et le mot-clé search permettent une recherche basée sur le sens -- génération automatique d'embeddings, indexation vectorielle HNSW et classement par similarité cosinus intégrés au langage.

Thales & Claude | March 30, 2026 9 min flin
EN/ FR/ ES
flinsemantic-searchvectorsembeddings

La recherche textuelle traditionnelle fait correspondre des mots. Vous cherchez « chaise » et trouvez des documents contenant le mot « chaise ». Mais vous manquez « siège », « tabouret », « fauteuil » et « assise » -- des mots qui signifient la même chose mais utilisent des lettres différentes. La recherche par mots-clés est rapide et prévisible, mais elle ne comprend pas le sens.

La recherche sémantique fait correspondre le sens. Vous cherchez « assise confortable pour bureau » et trouvez des produits décrits comme « chaise de bureau ergonomique », « tabouret pivotant réglable » et « siège bureau avec support lombaire » -- même si aucune de ces descriptions ne contient les mots « confortable » ou « assise ». La recherche comprend les concepts, pas seulement les caractères.

FLIN intègre la recherche sémantique dans le système de types. Un champ déclaré comme semantic text est automatiquement transformé en vecteur, indexé pour une recherche par similarité rapide et interrogeable avec le mot-clé search. Pas de Pinecone. Pas d'Elasticsearch. Pas de base de données vectorielle à configurer et maintenir.

Le type semantic text

Le modificateur semantic sur un champ texte indique à FLIN de générer des embeddings automatiquement :

flinentity Product {
    name: text                    // Texte normal -- correspondance exacte
    description: semantic text    // Sémantique -- recherche basée sur le sens
    sku: text                     // Texte normal -- identifiants
}

Lorsqu'un champ semantic text est sauvegardé, FLIN : 1. Stocke le texte original dans FlinDB. 2. Génère un embedding vectoriel en utilisant le modèle IA configuré. 3. Indexe l'embedding dans un index HNSW (Hierarchical Navigable Small World). 4. Associe l'embedding à l'instance d'entité.

Les quatre étapes se produisent de manière atomique lors du save. Le développeur écrit save product et l'embedding est généré. Il n'y a pas d'étape d'indexation séparée, pas de job batch, pas de processus de synchronisation.

Le mot-clé search effectue une recherche par similarité sémantique :

flinresults = search "comfortable seating for office"
          in Product
          by description
          limit 10

La syntaxe est : search "requête" in Entité by champ [limit N]

La chaîne de requête est transformée en embedding en utilisant le même modèle que le champ, puis comparée à tous les embeddings stockés en utilisant la similarité cosinus. Les résultats sont classés par score de similarité et les N premiers sont retournés comme entités FLIN typées.

flinentity Article {
    title: text
    content: semantic text
    summary: semantic text
}

// Rechercher par différents champs sémantiques
by_content = search "machine learning tutorials" in Article by content
by_summary = search "AI beginner guide" in Article by summary

Une entité peut avoir plusieurs champs sémantiques, chacun avec son propre index. Chercher par content compare avec le texte complet de l'article. Chercher par summary compare avec les résumés plus courts. Le choix dépend du cas d'utilisation -- recherche par contenu complet pour la précision, recherche par résumé pour la vitesse.

Comment fonctionnent les embeddings

Un embedding est un vecteur de nombres à virgule flottante (typiquement 384 à 1536 dimensions) qui représente le sens d'un texte. Des textes similaires produisent des vecteurs similaires. La distance entre les vecteurs est corrélée à la distance sémantique.

"comfortable office chair"    -> [0.12, -0.45, 0.78, 0.33, ...]
"ergonomic desk seating"      -> [0.11, -0.42, 0.76, 0.35, ...]
"kitchen table with drawers"  -> [-0.55, 0.23, 0.09, -0.41, ...]

Les deux premiers vecteurs sont proches (sens similaire). Le troisième est éloigné (concept différent). La similarité cosinus mesure cette distance :

similarity("comfortable office chair", "ergonomic desk seating") = 0.92
similarity("comfortable office chair", "kitchen table with drawers") = 0.23

L'index HNSW

La recherche par similarité en force brute compare le vecteur de requête à chaque vecteur stocké. C'est O(n) et devient inutilisable à grande échelle. FLIN utilise HNSW (Hierarchical Navigable Small World) pour la recherche approximative de plus proches voisins :

rustpub struct HnswIndex {
    layers: Vec<Vec<Node>>,
    entry_point: usize,
    max_connections: usize,
    ef_construction: usize,
}

impl HnswIndex {
    pub fn search(
        &self,
        query: &[f32],
        k: usize,
        ef_search: usize,
    ) -> Vec<(usize, f32)> {
        // Commencer de la couche supérieure, descendre à travers les couches
        let mut current = self.entry_point;

        for layer in (1..self.layers.len()).rev() {
            current = self.greedy_search(query, current, layer);
        }

        // Recherche exhaustive dans la couche inférieure avec largeur de faisceau ef_search
        self.beam_search(query, current, 0, ef_search, k)
    }
}

Propriétés HNSW : - Temps de requête : O(log n) en moyenne - Mémoire : O(n * d) où d est la dimension de l'embedding - Précision : >95% de rappel à des vitesses de recherche de millions par seconde - Temps d'insertion : O(log n) en moyenne

Pour une base de données de 100 000 produits, une requête de recherche sémantique se complète en moins de 5 millisecondes.

Génération d'embeddings

Les embeddings sont générés en utilisant le modèle IA configuré. FLIN prend en charge plusieurs fournisseurs d'embeddings :

flin// flin.config
{
    "ai": {
        "provider": "anthropic",
        "model": "claude-3-haiku",
        "embedding_model": "text-embedding-3-small"
    }
}

Pour les cas d'utilisation hors ligne ou à faible latence, FLIN prend en charge la génération locale d'embeddings via FastEmbed (couvert dans l'article 119).

Embedding automatique lors de la sauvegarde

Lorsqu'une entité avec un champ semantic text est sauvegardée, l'embedding est généré automatiquement :

flinproduct = Product {
    name: "Ergonomic Office Chair",
    description: "A comfortable chair designed for long work sessions with adjustable lumbar support, breathable mesh back, and 360-degree swivel base.",
    sku: "CHAIR-ERG-001"
}

save product  // Embedding généré ici pour le champ description

Si la description est mise à jour, l'embedding est regénéré :

flinproduct = Product.find(42)
product.description = "Updated description with new features..."
save product  // Embedding regénéré

L'ancien embedding est remplacé de manière atomique. Il n'y a pas de problème d'index obsolète.

Champs sémantiques multiples

Les entités peuvent avoir plusieurs champs sémantiques, chacun interrogeable indépendamment :

flinentity Job {
    title: text
    description: semantic text
    requirements: semantic text
    benefits: semantic text
}

// Rechercher différents aspects de la même entité
by_desc = search "remote engineering position" in Job by description
by_reqs = search "python and kubernetes experience" in Job by requirements
by_perks = search "health insurance and remote work" in Job by benefits

Chaque champ sémantique a son propre index HNSW. Les indices sont indépendants -- mettre à jour la description n'affecte pas l'index des exigences.

Recherche dans les templates

La recherche sémantique s'intègre naturellement avec les templates de vue de FLIN :

flin// app/products.flin

query = ""

<input placeholder="Rechercher des produits..."
       value={query}
       input={results = search query in Product by description limit 20}>

{if query.len > 3}
    {for product in results}
        <div class="product-card">
            <h3>{product.name}</h3>
            <p>{product.description}</p>
            <span class="price">${product.price}</span>
        </div>
    {/for}
{/if}

Au fur et à mesure que l'utilisateur tape, la recherche se déclenche à chaque événement d'entrée. Les résultats se mettent à jour de manière réactive. L'ensemble de l'expérience de recherche -- de la frappe aux résultats affichés -- est construit avec le système de réactivité standard de FLIN.

Caractéristiques de performance

OpérationTempsNotes
Génération d'embedding (API)100-300 msDépend de la longueur du texte et du fournisseur
Génération d'embedding (local)10-50 msAvec FastEmbed
Insertion HNSW< 1 msPar document
Recherche HNSW (10K docs)< 2 msTop 10 résultats
Recherche HNSW (100K docs)< 5 msTop 10 résultats
Recherche HNSW (1M docs)< 15 msTop 10 résultats

Le goulot d'étranglement est la génération d'embeddings, pas la recherche. Pour les cas d'utilisation interactifs (comme l'exemple de recherche en temps réel ci-dessus), la génération locale d'embeddings avec FastEmbed est recommandée pour maintenir la latence sous 50 ms.

Quand utiliser semantic vs texte normal

Utiliser sémantiqueUtiliser normal
Longues descriptionsNoms et labels courts
Contenu généré par l'utilisateurIdentifiants structurés (SKU, ID)
Champs à forte rechercheChamps de correspondance exacte
Contenu en langage naturelCodes, énumérations, valeurs de statut
Formulations multiples possiblesValeurs canoniques

Le modificateur semantic ajoute un surcoût de stockage (vecteur d'embedding par enregistrement) et une latence d'écriture (génération d'embedding lors de la sauvegarde). Utilisez-le pour les champs où la recherche basée sur le sens apporte de la valeur, pas pour chaque champ texte.

Considérations de confidentialité

La génération d'embeddings nécessite l'envoi de texte à un fournisseur IA (sauf en utilisant des embeddings locaux). FLIN traite cela :

  • Seuls les champs sémantiques sont envoyés pour l'embedding. Les champs texte normaux, les mots de passe et autres données d'entités restent locaux.
  • Texte, pas contexte. La valeur du champ est envoyée pour l'embedding, pas la structure de l'entité ou les données connexes.
  • Option locale. FastEmbed génère des embeddings localement sans aucun appel réseau.

Pour les applications avec des exigences strictes de résidence des données, l'embedding local avec FastEmbed élimine toute transmission de données externe.

La recherche sémantique transforme la façon dont les utilisateurs interagissent avec les données. Au lieu de leur demander de connaître les mots-clés exacts, les catégories ou les tags, ils décrivent ce qu'ils veulent en langage naturel et FLIN trouve les correspondances les plus proches. Dans le prochain article, nous explorons la passerelle IA -- comment FLIN se connecte à huit fournisseurs IA différents à travers une seule API unifiée.


Ceci est la partie 117 de la série « Comment nous avons construit FLIN », documentant comment un CEO à Abidjan et un CTO IA ont conçu et construit un langage de programmation à partir de zéro.

Navigation de la série : - [116] Le moteur d'intentions : requêtes base de données en langage naturel - [117] Recherche sémantique et stockage vectoriel (vous êtes ici) - [118] Passerelle IA : 8 fournisseurs, une seule API - [119] Intégration FastEmbed pour les embeddings

Share this article:

Responses

Write a response
0/2000
Loading responses...

Related Articles