Générer des embeddings pour vos données
Objectifs
- Préparer vos données textuelles pour l’embedding
- Générer des embeddings efficacement à grande échelle
- Stocker les vecteurs pour une utilisation ultérieure
Préparer vos données
La qualité de vos embeddings dépend directement de la qualité de vos données. Avant de générer des vecteurs, nettoyez et normalisez vos textes.
Nettoyage de base
import re
def nettoyer_texte(texte: str) -> str:
"""Prépare un texte pour l'embedding."""
# Supprimer les espaces multiples
texte = re.sub(r"\s+", " ", texte)
# Supprimer les caractères de contrôle
texte = re.sub(r"[\x00-\x08\x0b\x0c\x0e-\x1f]", "", texte)
# Trim
texte = texte.strip()
return texte
# Exemple
brut = " Texte avec des espaces\n\n\nen trop "
propre = nettoyer_texte(brut)
print(propre) # "Texte avec des espaces en trop"
Enrichir le contexte
Pour améliorer la qualité des embeddings, ajoutez du contexte au texte brut. Par exemple, pour des articles de documentation :
def enrichir_document(titre: str, section: str, contenu: str) -> str:
"""Crée un texte enrichi pour un meilleur embedding."""
return f"Titre : {titre}\nSection : {section}\n\n{contenu}"
texte_enrichi = enrichir_document(
titre="Installation de PostgreSQL",
section="Guide de démarrage",
contenu="Téléchargez le package depuis le site officiel..."
)
Générer des embeddings en lots
Pour un corpus réel, vous aurez des centaines ou des milliers de documents. Voici un pipeline robuste :
from openai import OpenAI
import time
import json
client = OpenAI()
def generer_embeddings(
textes: list[str],
model: str = "text-embedding-3-large",
batch_size: int = 100
) -> list[list[float]]:
"""Génère des embeddings par lots avec gestion des erreurs."""
tous_les_embeddings = []
for i in range(0, len(textes), batch_size):
batch = textes[i:i + batch_size]
print(f"Traitement du lot {i // batch_size + 1}/"
f"{(len(textes) - 1) // batch_size + 1}")
try:
response = client.embeddings.create(
input=batch,
model=model
)
# Trier par index pour garantir l'ordre
batch_embeddings = sorted(
response.data, key=lambda x: x.index
)
tous_les_embeddings.extend(
[item.embedding for item in batch_embeddings]
)
except Exception as e:
print(f"Erreur sur le lot {i}: {e}")
# Retry après une pause
time.sleep(5)
response = client.embeddings.create(
input=batch,
model=model
)
batch_embeddings = sorted(
response.data, key=lambda x: x.index
)
tous_les_embeddings.extend(
[item.embedding for item in batch_embeddings]
)
return tous_les_embeddings
Stocker les embeddings
Format JSON simple
Pour un petit corpus (quelques milliers de documents), un fichier JSON suffit :
import json
documents = [
{"id": 1, "texte": "Premier document...", "metadata": {"source": "faq"}},
{"id": 2, "texte": "Deuxième document...", "metadata": {"source": "docs"}},
]
# Générer les embeddings
textes = [d["texte"] for d in documents]
embeddings = generer_embeddings(textes)
# Ajouter les vecteurs aux documents
for doc, emb in zip(documents, embeddings):
doc["embedding"] = emb
# Sauvegarder
with open("corpus_embeddings.json", "w") as f:
json.dump(documents, f)
Format NumPy pour la performance
Pour de plus gros volumes, NumPy est plus efficace :
import numpy as np
# Convertir en matrice NumPy
matrice = np.array(embeddings, dtype=np.float32)
print(f"Shape : {matrice.shape}") # (n_docs, 3072)
# Sauvegarder au format binaire
np.save("embeddings.npy", matrice)
# Charger
matrice_chargee = np.load("embeddings.npy")
Pipeline complet : de fichiers texte à embeddings
Voici un exemple complet qui lit des fichiers, génère les embeddings et les stocke :
from openai import OpenAI
from pathlib import Path
import json
import numpy as np
client = OpenAI()
def pipeline_embeddings(dossier: str, model: str = "text-embedding-3-large"):
"""Pipeline complet : fichiers → embeddings → stockage."""
dossier_path = Path(dossier)
# 1. Lire les fichiers
documents = []
for fichier in sorted(dossier_path.glob("*.txt")):
contenu = fichier.read_text(encoding="utf-8")
contenu = nettoyer_texte(contenu)
if contenu:
documents.append({
"id": fichier.stem,
"fichier": fichier.name,
"texte": contenu
})
print(f"{len(documents)} documents trouvés")
# 2. Générer les embeddings
textes = [d["texte"] for d in documents]
embeddings = generer_embeddings(textes, model=model)
# 3. Sauvegarder
# Métadonnées en JSON
meta = [{"id": d["id"], "fichier": d["fichier"]} for d in documents]
with open("metadata.json", "w") as f:
json.dump(meta, f, ensure_ascii=False, indent=2)
# Vecteurs en NumPy
np.save("embeddings.npy", np.array(embeddings, dtype=np.float32))
print(f"Embeddings sauvegardés : {len(embeddings)} vecteurs "
f"de {len(embeddings[0])} dimensions")
return documents, embeddings
# Utilisation
documents, embeddings = pipeline_embeddings("./mes_documents/")
Estimer les coûts
Avant de lancer un gros traitement, estimez le nombre de tokens :
import tiktoken
encoder = tiktoken.get_encoding("cl100k_base")
def estimer_cout(textes: list[str], model: str = "text-embedding-3-large"):
"""Estime le coût d'embedding pour une liste de textes."""
total_tokens = sum(len(encoder.encode(t)) for t in textes)
# Prix approximatifs par million de tokens (vérifiez les tarifs actuels)
prix = {
"text-embedding-3-large": 0.13,
"text-embedding-3-small": 0.02,
}
cout = total_tokens / 1_000_000 * prix.get(model, 0.13)
print(f"Tokens estimés : {total_tokens:,}")
print(f"Coût estimé : ${cout:.4f}")
return total_tokens, cout
Résumé
- Nettoyez et enrichissez vos textes avant de générer des embeddings
- Utilisez le traitement par lots (batch) pour les gros corpus
- Stockez les métadonnées en JSON et les vecteurs en NumPy
- Estimez vos coûts avant de lancer un traitement massif