Kennisbank › Ai Maatjes › Vecteurs d’embedding expliqués pour les développeurs
ai maatjes expert 26 August 2026

Vecteurs d’embedding expliqués pour les développeurs

Cet article explique comment fonctionnent les embeddings vectoriels et comment vous pouvez les utiliser concrètement pour des recherches sémantiques, spécifiquement pour les développeurs qui travaillent avec Python et

Cet article explique comment fonctionnent les vector embeddings et comment les utiliser concrètement pour des recherches sémantiques, spécifiquement pour les développeurs qui travaillent avec Python et l'API d'OpenAI.

Prérequis

- Python 3.10 ou supérieur - Paquet Python `openai` version 1.35.0 ou supérieure - Une clé API OpenAI avec accès au modèle `text-embedding-3-small` - `numpy` version 1.26.0 ou supérieure pour les calculs vectoriels

Installez les dépendances :

pip install openai==1.35.0 numpy==1.26.0

Étapes

1. Créez un embedding

Un embedding est une liste de nombres à virgule flottante qui représente la signification sémantique d'un texte. Le modèle `text-embedding-3-small` d'OpenAI convertit le texte en un vecteur de 1536 dimensions.

from openai import OpenAI</p><p>client = OpenAI(api_key="votre-clé-api")</p><p>response = client.embeddings.create(
    model="text-embedding-3-small",
    input="Le chat est assis sur le tapis"
)</p><p>embedding = response.data[0].embedding
print(len(embedding))  Output: 1536

2. Stockez les embeddings dans une base de données vectorielle

Pour la production, utilisez une base de données vectorielle dédiée comme Pinecone, Weaviate ou pgvector. Pour le développement local, un tableau NumPy suffit.

import numpy as np</p><p>Stockez les embeddings comme matrice
documents = [
    "Le chat est assis sur le tapis",
    "Le chien court dans le parc",
    "Un oiseau vole au-dessus de l'eau"
]</p><p>embeddings = []
for doc in documents:
    response = client.embeddings.create(
        model="text-embedding-3-small",
        input=doc
    )
    embeddings.append(response.data[0].embedding)</p><p>embedding_matrix = np.array(embeddings)
np.save('document_embeddings.npy', embedding_matrix)

3. Calculez la similarité cosinus

La similarité cosinus mesure l'angle entre deux vecteurs. Une valeur de 1 signifie identique, 0 signifie aucune superposition. C'est la méthode standard pour déterminer la similarité sémantique.

def cosine_similarity(vec_a, vec_b):
    dot_product = np.dot(vec_a, vec_b)
    norm_a = np.linalg.norm(vec_a)
    norm_b = np.linalg.norm(vec_b)
    return dot_product / (norm_a * norm_b)</p><p>Testez avec deux phrases liées
query = "Un matou est couché sur le sol"
query_response = client.embeddings.create(
    model="text-embedding-3-small",
    input=query
)
query_embedding = query_response.data[0].embedding</p><p>similarities = [
    cosine_similarity(query_embedding, doc_emb)
    for doc_emb in embeddings
]</p><p>print(similarities)
Output: [0.82, 0.31, 0.28] — la première phrase est la plus liée

4. Construisez une fonction de recherche sémantique

Les recherches sémantiques trouvent des résultats en fonction du sens, pas d'une correspondance exacte de mots. Cela fonctionne parce que les embeddings placent les mots ayant des significations similaires proches les uns des autres dans l'espace vectoriel.

def semantic_search(query, embeddings, documents, top_k=3):
    query_response = client.embeddings.create(
        model="text-embedding-3-small",
        input=query
    )
    query_embedding = query_response.data[0].embedding
    
    similarities = [
        cosine_similarity(query_embedding, doc_emb)
        for doc_emb in embeddings
    ]
    
    top_indices = np.argsort(similarities)[-top_k:][::-1]
    
    results = []
    for idx in top_indices:
        results.append({
            'document': documents[idx],
            'similarity': similarities[idx]
        })
    
    return results</p><p>results = semantic_search("Un animal dort", embeddings, documents)
for r in results:
    print(f"{r['similarity']:.2f}: {r['document']}")
Output:
0.79: Le chat est assis sur le tapis
0.45: Le chien court dans le parc
0.33: Un oiseau vole au-dessus de l'eau

5. Réduisez la dimensionnalité avec l'ACP

1536 dimensions, c'est beaucoup pour la visualisation ou le stockage en mémoire. L'analyse en composantes principales (ACP) réduit la dimensionnalité tout en préservant les distances relatives.

from sklearn.decomposition import PCA</p><p>pca = PCA(n_components=2)
reduced_embeddings = pca.fit_transform(embedding_matrix)</p><p>print(reduced_embeddings.shape)  Output: (3, 2)

6. Implémentez la mise en cache des embeddings

Générer des embeddings coûte des appels API et du temps. Mettez-les en cache localement pour éviter des calculs répétés.

import json
import hashlib
from pathlib import Path</p><p>CACHE_FILE = Path("embedding_cache.json")</p><p>def get_cached_embedding(text):
    if CACHE_FILE.exists():
        cache = json.loads(CACHE_FILE.read_text())
    else:
        cache = {}
    
    text_hash = hashlib.sha256(text.encode()).hexdigest()
    
    if text_hash in cache:
        return cache[text_hash]
    
    response = client.embeddings.create(
        model="text-embedding-3-small",
        input=text
    )
    embedding = response.data[0].embedding
    
    cache[text_hash] = embedding
    CACHE_FILE.write_text(json.dumps(cache))
    
    return embedding</p><p>Utilisez le cache
emb = get_cached_embedding("Le chat est assis sur le tapis")  Appel API
emb_cached = get_cached_embedding("Le chat est assis sur le tapis")  Depuis le cache

7. Traitement par lots pour l'efficacité

Traitez plusieurs documents en un seul appel API. Cela réduit considérablement la latence et les coûts.

texts = [
    "Eerste document over kunstmatige intelligentie",
    "Tweede document over machine learning",
    "Derde document over natuurlijke taalverwerking"
]</p><p>batch_response = client.embeddings.create(
    model="text-embedding-3-small",
    input=texts
)</p><p>batch_embeddings = [item.embedding for item in batch_response.data]
print(len(batch_embeddings))  Output: 3

8. Implémentez un pipeline de recherche complet

Combinez toutes les étapes dans un pipeline réutilisable que vous pouvez intégrer directement dans une application.

class EmbeddingSearch:
    def __init__(self, model="text-embedding-3-small"):
        self.client = OpenAI()
        self.model = model
        self.documents = []
        self.embeddings = np.array([])
    
    def add_documents(self, docs):
        self.documents.extend(docs)
        response = self.client.embeddings.create(
            model=self.model,
            input=docs
        )
        new_embeddings = np.array([item.embedding for item in response.data])
        
        if self.embeddings.size == 0:
            self.embeddings = new_embeddings
        else:
            self.embeddings = np.vstack([self.embeddings, new_embeddings])
    
    def search(self, query, top_k=5):
        response = self.client.embeddings.create(
            model=self.model,
            input=query
        )
        query_embedding = np.array(response.data[0].embedding)
        
        similarities = [
            cosine_similarity(query_embedding, doc_emb)
            for doc_emb in self.embeddings
        ]
        
        top_indices = np.argsort(similarities)[-top_k:][::-1]
        
        return [
            (self.documents[idx], similarities[idx])
            for idx in top_indices
        ]</p><p>Utilisez le pipeline
search_engine = EmbeddingSearch()
search_engine.add_documents(documents)
results = search_engine.search("Comment fonctionne un chat ?", top_k=2)</p><p>for doc, score in results:
    print(f"{score:.3f} - {doc}")

Vérification

Vérifiez que vos embeddings fonctionnent correctement en testant la dimensionnalité et les relations sémantiques :

python -c "
from openai import OpenAI
import numpy as np</p><p>client = OpenAI()
response = client.embeddings.create(
    model='text-embedding-3-small',
    input=['chien', 'chat', 'voiture']
)
embeddings = np.array([item.embedding for item in response.data])</p><p>Vérification de la dimensionnalité
assert embeddings.shape == (3, 1536), f'Erreur : attendu (3, 1536), reçu {embeddings.shape}'</p><p>Vérification des relations sémantiques
def cos_sim(a, b):
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))</p><p>chien_chat = cos_sim(embeddings[0], embeddings[1])
chien_voiture = cos_sim(embeddings[0], embeddings[2])</p><p>print(f'Dimensionnalité : {embeddings.shape[1]}')
print(f'Similarité chien vs chat : {chien_chat:.3f}')
print(f'Similarité chien vs voiture : {chien_voiture:.3f}')
assert chien_chat > chien_voiture, 'La relation sémantique n'est pas correcte'
print('Toutes les vérifications ont réussi')
"

Problèmes fréquents

1. Erreur API : "model_not_found"

Votre clé API n'a pas accès au modèle `text-embedding-3-small`. Utilisez une version plus ancienne du modèle ou mettez à niveau votre compte.

Solution : Remplacez `text-embedding-3-small` par `text-embedding-ada-002` et ajustez la dimensionnalité de 1536 à 3072.

2. Scores de similarité faibles pour des textes liés

Les embeddings fonctionnent bien pour la similarité sémantique, mais pas pour la correspondance exacte des mots. Deux phrases avec les mêmes mots mais dans un ordre différent peuvent donner des scores faibles.

Solution : Combinez les embeddings avec une méthode de recherche lexicale comme BM25 pour des recherches hybrides. Utilisez `text-embedding-3-large` pour une meilleure précision sémantique.

3. Problèmes de mémoire avec beaucoup de documents

Le stockage de centaines de milliers d'embeddings de 1536 dimensions consomme beaucoup de RAM. Un million de documents utilise environ 6 Go.

Solution : Utilisez une base de données vectorielle dédiée comme Pinecone ou Weaviate. Elles stockent les embeddings sur disque et utilisent des algorithmes de plus proche voisin approximatif (ANN) pour des recherches rapides.

Le passage du texte brut aux embeddings est un changement fondamental : votre code ne travaille plus avec des mots, mais avec des positions dans un espace vectoriel continu — et cet espace détermine en fin de compte ce que votre moteur de recherche trouve ou ne trouve pas.

← Retour à la base de connaissances
← Terug naar kennisbank