
ChromaDB est une base de données vectorielle open source qui stocke vos documents sous forme d’embeddings et permet la recherche sémantique en quelques lignes de Python. Dans ce guide, vous allez créer votre première collection, indexer des documents et interroger ChromaDB — le tout avec du code testé sur la version 1.5.0.
Pourquoi ChromaDB
Section intitulée « Pourquoi ChromaDB »ChromaDB se distingue par sa simplicité d’utilisation : pas besoin de serveur externe pour commencer, les embeddings sont générés automatiquement si vous ne fournissez pas les vôtres, et l’API Python est intuitive.
| Caractéristique | Ce que ChromaDB offre |
|---|---|
| Démarrage rapide | pip install chromadb + 5 lignes de code |
| Embeddings auto | Modèle par défaut (all-MiniLM-L6-v2) inclus |
| Persistance native | Stockage SQLite local, pas de serveur requis |
| Filtrage métadonnées | Requêtes combinant sémantique + attributs |
| Full-text search | $contains, $regex sur les documents |
Cas d’usage typiques :
- RAG : stocker les chunks de documentation pour un assistant
- Recherche sémantique : trouver des articles similaires
- Mémoire d’agent : historique de conversations pour LLM
- Recommandations : produits ou contenus similaires
Prérequis et installation
Section intitulée « Prérequis et installation »# Python 3.10+ requispython3 --version
# Créer un environnement dédiépython3 -m venv chroma-envsource chroma-env/bin/activate # Linux/Mac
# Installer ChromaDBpip install chromadbVérifiez l’installation :
import chromadbprint(f"ChromaDB version: {chromadb.__version__}")Les trois modes de client
Section intitulée « Les trois modes de client »ChromaDB propose trois façons de se connecter selon votre contexte :
Mode in-memory (développement)
Section intitulée « Mode in-memory (développement) »Le plus simple pour expérimenter. Les données restent en mémoire et sont perdues à l’arrêt du script.
import chromadb
# Client éphémère — idéal pour les notebooksclient = chromadb.Client()
# Créer une collection de testcollection = client.create_collection("test")print(f"Collection créée: {collection.name}")Mode persistant (local)
Section intitulée « Mode persistant (local) »Les données sont sauvegardées sur disque dans un dossier SQLite. C’est le mode recommandé pour le développement local et les petits projets.
import chromadb
# Les données seront sauvées dans ./chroma_db/client = chromadb.PersistentClient(path="./chroma_db")
# La collection persiste entre les exécutionscollection = client.get_or_create_collection("docs")print(f"Documents: {collection.count()}")Mode client-serveur (production)
Section intitulée « Mode client-serveur (production) »Pour les déploiements multi-utilisateurs, lancez ChromaDB comme serveur :
# Démarrer le serveur (port 8000 par défaut)chroma run --host 0.0.0.0 --port 8000 --path ./chroma_serverPuis connectez-vous depuis votre application :
import chromadb
client = chromadb.HttpClient(host="localhost", port=8000)collection = client.get_or_create_collection("production_docs")Créer et gérer des collections
Section intitulée « Créer et gérer des collections »Une collection dans ChromaDB est l’équivalent d’une table. Elle contient vos documents, leurs embeddings et les métadonnées associées.
Créer une collection
Section intitulée « Créer une collection »import chromadb
client = chromadb.PersistentClient(path="./chroma_db")
# Créer une collection simplecollection = client.create_collection( name="runbooks", metadata={ "description": "Documentation opérationnelle", "hnsw:space": "cosine" # Distance : cosine, l2, ou ip })print(f"Collection '{collection.name}' créée")Le paramètre hnsw:space définit la métrique de distance :
| Métrique | Usage | Notes |
|---|---|---|
cosine | Texte, embeddings normalisés | Recommandé par défaut |
l2 | Distance euclidienne | Embeddings non normalisés |
ip | Produit scalaire | Cas spécifiques |
Lister et récupérer des collections
Section intitulée « Lister et récupérer des collections »# Lister toutes les collectionscollections = client.list_collections()for coll in collections: print(f"- {coll.name}: {coll.count()} documents")
# Récupérer une collection existantecollection = client.get_collection("runbooks")
# Récupérer ou créer si n'existe pascollection = client.get_or_create_collection("runbooks")Supprimer une collection
Section intitulée « Supprimer une collection »# Attention : suppression irréversible !client.delete_collection("collection_obsolete")Ajouter des documents
Section intitulée « Ajouter des documents »Vous pouvez ajouter des documents de deux façons : en laissant ChromaDB générer les embeddings automatiquement, ou en fournissant vos propres vecteurs.
Avec génération automatique des embeddings
Section intitulée « Avec génération automatique des embeddings »C’est le cas le plus simple. ChromaDB utilise le modèle all-MiniLM-L6-v2 par défaut.
# Ajouter des documents avec embeddings auto-généréscollection.add( ids=["doc1", "doc2", "doc3"], documents=[ "Kubernetes orchestre les conteneurs à grande échelle", "Docker permet de créer des images de conteneurs", "Ansible automatise la configuration des serveurs" ], metadatas=[ {"source": "runbook-k8s.md", "category": "orchestration"}, {"source": "guide-docker.md", "category": "conteneurs"}, {"source": "guide-ansible.md", "category": "automation"} ])print(f"Documents ajoutés: {collection.count()}")Ce qui se passe :
- ChromaDB charge le modèle d’embedding (premier appel uniquement)
- Chaque document est transformé en vecteur de 384 dimensions
- Les vecteurs sont indexés dans un index HNSW
- Les documents et métadonnées sont stockés pour être retournés
Avec vos propres embeddings
Section intitulée « Avec vos propres embeddings »Si vous utilisez un autre modèle (OpenAI, Voyage, E5…), passez directement les vecteurs :
from sentence_transformers import SentenceTransformer
# Charger votre modèlemodel = SentenceTransformer("intfloat/multilingual-e5-small")
documents = [ "Kubernetes gère les pods et les services", "Terraform provisionne l'infrastructure cloud"]
# Générer les embeddings vous-mêmeembeddings = model.encode(documents).tolist()
# Ajouter avec embeddings pré-calculéscollection.add( ids=["doc4", "doc5"], documents=documents, embeddings=embeddings, metadatas=[ {"source": "k8s.md"}, {"source": "terraform.md"} ])Upsert : ajouter ou mettre à jour
Section intitulée « Upsert : ajouter ou mettre à jour »upsert insère les nouveaux documents et met à jour les existants (par ID) :
# Si doc1 existe, il sera mis à jour ; sinon, il sera créécollection.upsert( ids=["doc1", "doc6"], documents=[ "Kubernetes v1.29 orchestre les conteneurs (mis à jour)", "Nouveau document sur Helm" ], metadatas=[ {"source": "runbook-k8s.md", "version": "1.29"}, {"source": "guide-helm.md"} ])Mettre à jour des documents existants
Section intitulée « Mettre à jour des documents existants »# Mettre à jour uniquement doc1collection.update( ids=["doc1"], documents=["Kubernetes v1.30 orchestre les conteneurs"], metadatas=[{"source": "runbook-k8s.md", "version": "1.30"}])Supprimer des documents
Section intitulée « Supprimer des documents »# Par IDscollection.delete(ids=["doc1", "doc2"])
# Par filtre sur les métadonnéescollection.delete(where={"category": "obsolete"})
# Par filtre sur le contenucollection.delete(where_document={"$contains": "deprecated"})Recherche sémantique avec query
Section intitulée « Recherche sémantique avec query »La méthode query effectue une recherche par similarité : elle retourne les documents dont le sens est le plus proche de votre requête.
Recherche simple
Section intitulée « Recherche simple »results = collection.query( query_texts=["comment déployer une application"], n_results=3)
# Afficher les résultatsfor i, (doc, dist) in enumerate(zip( results['documents'][0], results['distances'][0])): print(f"{i+1}. (distance: {dist:.4f}) {doc[:80]}...")Sortie typique :
1. (distance: 0.1056) Kubernetes orchestre les conteneurs à grande échelle...2. (distance: 0.1089) Docker permet de créer des images de conteneurs...3. (distance: 0.1368) Terraform provisionne l'infrastructure cloud...Choisir ce qui est retourné
Section intitulée « Choisir ce qui est retourné »Par défaut, query retourne documents, metadatas et distances. Utilisez include pour personnaliser :
results = collection.query( query_texts=["monitoring kubernetes"], n_results=5, include=["documents", "metadatas", "distances", "embeddings"])
# Les embeddings sont maintenant inclusprint(f"Embedding dimension: {len(results['embeddings'][0][0])}")# Embedding dimension: 384Recherche avec vos propres embeddings
Section intitulée « Recherche avec vos propres embeddings »Si vous avez généré l’embedding de la requête vous-même :
query_embedding = model.encode(["comment monitorer un cluster"]).tolist()
results = collection.query( query_embeddings=query_embedding, n_results=5)Filtrage par métadonnées
Section intitulée « Filtrage par métadonnées »Combinez la recherche sémantique avec des filtres sur les métadonnées pour des résultats plus précis.
Opérateurs de comparaison
Section intitulée « Opérateurs de comparaison »| Opérateur | Description | Exemple |
|---|---|---|
$eq | Égal (implicite) | {"level": "advanced"} |
$ne | Différent | {"status": {"$ne": "draft"}} |
$gt, $gte | Plus grand (ou égal) | {"score": {"$gte": 0.8}} |
$lt, $lte | Plus petit (ou égal) | {"date": {"$lt": "2024-01-01"}} |
$in | Dans la liste | {"tag": {"$in": ["k8s", "docker"]}} |
$nin | Pas dans la liste | {"env": {"$nin": ["dev", "test"]}} |
Exemples de filtrage
Section intitulée « Exemples de filtrage »# Filtrer par valeur exacteresults = collection.query( query_texts=["déploiement"], n_results=5, where={"source": "runbook-k8s.md"})
# Filtrer avec opérateurresults = collection.query( query_texts=["sécurité"], n_results=5, where={"score": {"$gte": 0.7}})
# Filtrer avec $inresults = collection.query( query_texts=["automatisation"], n_results=5, where={"category": {"$in": ["automation", "orchestration"]}})Opérateurs logiques $and et $or
Section intitulée « Opérateurs logiques $and et $or »# Combiner avec $andresults = collection.query( query_texts=["configuration"], n_results=5, where={ "$and": [ {"category": "automation"}, {"level": {"$in": ["intermediate", "advanced"]}} ] })
# Combiner avec $orresults = collection.query( query_texts=["conteneurs"], n_results=5, where={ "$or": [ {"source": "guide-docker.md"}, {"source": "runbook-k8s.md"} ] })Métadonnées avec tableaux
Section intitulée « Métadonnées avec tableaux »Vous pouvez stocker des listes dans les métadonnées et filtrer avec $contains :
# Ajouter un document avec des tags (tableau)collection.upsert( ids=["multi-tags"], documents=["Guide complet Docker, Kubernetes et CI/CD"], metadatas=[{ "tags": ["docker", "kubernetes", "cicd"], "versions": [1, 2, 3] }])
# Filtrer sur un élément du tableauresults = collection.get( where={"tags": {"$contains": "kubernetes"}})print(f"Documents avec tag kubernetes: {len(results['ids'])}")Full-text search et regex
Section intitulée « Full-text search et regex »En plus de la recherche sémantique, ChromaDB permet de filtrer par contenu textuel exact.
Recherche avec $contains
Section intitulée « Recherche avec $contains »# Documents contenant exactement "Kubernetes"results = collection.get( where_document={"$contains": "Kubernetes"})
# Combiné avec query sémantiqueresults = collection.query( query_texts=["déploiement"], n_results=5, where_document={"$contains": "kubectl"})Recherche avec regex
Section intitulée « Recherche avec regex »# Insensible à la casse avec regexresults = collection.get( where_document={"$regex": "(?i)kubernetes"})
# Trouver des patterns spécifiques (ex: versions)results = collection.get( where_document={"$regex": "v1\\.[0-9]+"})Combiner where et where_document
Section intitulée « Combiner where et where_document »# Sémantique + métadonnées + contenuresults = collection.query( query_texts=["sécurité"], n_results=5, where={"source": "runbook-k8s.md"}, where_document={"$contains": "secret"})Embedding functions personnalisées
Section intitulée « Embedding functions personnalisées »Par défaut, ChromaDB utilise all-MiniLM-L6-v2. Pour du contenu multilingue ou des besoins spécifiques, utilisez une fonction d’embedding personnalisée.
Avec sentence-transformers
Section intitulée « Avec sentence-transformers »from chromadb.utils.embedding_functions import SentenceTransformerEmbeddingFunction
# Modèle multilingue recommandé pour le françaisembedding_fn = SentenceTransformerEmbeddingFunction( model_name="intfloat/multilingual-e5-small")
collection = client.create_collection( name="docs_fr", embedding_function=embedding_fn, metadata={"hnsw:space": "cosine"})Modèles recommandés
Section intitulée « Modèles recommandés »| Modèle | Dimensions | Langues | Usage |
|---|---|---|---|
all-MiniLM-L6-v2 | 384 | Anglais | Défaut, rapide |
intfloat/multilingual-e5-small | 384 | 100+ | Multilingue, recommandé FR |
BAAI/bge-m3 | 1024 | 100+ | Haute qualité, plus lent |
Important sur la récupération
Section intitulée « Important sur la récupération »Quand vous récupérez une collection existante avec get_collection, vous devez passer la même fonction d’embedding :
# ❌ Ne fonctionnera pas correctement (embedding par défaut utilisé)collection = client.get_collection("docs_fr")
# ✅ Passer la fonction d'embeddingembedding_fn = SentenceTransformerEmbeddingFunction( model_name="intfloat/multilingual-e5-small")collection = client.get_collection("docs_fr", embedding_function=embedding_fn)Exemple complet : RAG avec ChromaDB
Section intitulée « Exemple complet : RAG avec ChromaDB »Voici un exemple complet d’utilisation de ChromaDB pour un système RAG simple.
"""RAG simple avec ChromaDB."""import chromadbfrom chromadb.utils.embedding_functions import SentenceTransformerEmbeddingFunction
def creer_collection_rag(client, nom: str): """Crée une collection optimisée pour le RAG.""" embedding_fn = SentenceTransformerEmbeddingFunction( model_name="intfloat/multilingual-e5-small" ) return client.get_or_create_collection( name=nom, embedding_function=embedding_fn, metadata={"hnsw:space": "cosine"} )
def indexer_documents(collection, documents: list[dict]): """ Indexe une liste de documents dans la collection.
Chaque document doit avoir : id, content, source, section """ collection.upsert( ids=[d["id"] for d in documents], documents=[d["content"] for d in documents], metadatas=[{"source": d["source"], "section": d["section"]} for d in documents] ) return collection.count()
def rechercher(collection, question: str, top_k: int = 3, source: str = None): """ Recherche les chunks pertinents pour une question.
Args: collection: Collection ChromaDB question: Question utilisateur top_k: Nombre de résultats source: Filtrer par source (optionnel)
Returns: Liste de chunks avec métadonnées et distances """ where = {"source": source} if source else None
results = collection.query( query_texts=[question], n_results=top_k, where=where )
# Reformater les résultats chunks = [] for i in range(len(results['ids'][0])): chunks.append({ "id": results['ids'][0][i], "content": results['documents'][0][i], "metadata": results['metadatas'][0][i], "distance": results['distances'][0][i] }) return chunks
def formater_contexte(chunks: list[dict]) -> str: """Formate les chunks pour injection dans le prompt.""" contexte = [] for chunk in chunks: source = chunk['metadata'].get('source', 'unknown') section = chunk['metadata'].get('section', '') contexte.append(f"[Source: {source} - {section}]\n{chunk['content']}") return "\n---\n".join(contexte)
# === Utilisation ===if __name__ == "__main__": # Initialiser client = chromadb.PersistentClient(path="./rag_db") collection = creer_collection_rag(client, "documentation")
# Indexer des documents docs = [ { "id": "k8s-deploy-1", "content": "Pour déployer sur Kubernetes, utilisez kubectl apply -f deployment.yaml", "source": "runbook-k8s.md", "section": "deployment" }, { "id": "k8s-secret-1", "content": "Les secrets Kubernetes sont encodés en base64, pas chiffrés. Utilisez Sealed Secrets ou Vault.", "source": "runbook-k8s.md", "section": "security" }, { "id": "ansible-1", "content": "Ansible utilise des playbooks YAML pour décrire l'état souhaité des serveurs.", "source": "guide-ansible.md", "section": "basics" }, ] count = indexer_documents(collection, docs) print(f"Documents indexés: {count}")
# Rechercher question = "Comment sécuriser mes secrets Kubernetes ?" chunks = rechercher(collection, question, top_k=2)
print(f"\nQuestion: {question}") print(f"\nContexte RAG:\n{formater_contexte(chunks)}")Sortie :
Documents indexés: 3
Question: Comment sécuriser mes secrets Kubernetes ?
Contexte RAG:[Source: runbook-k8s.md - security]Les secrets Kubernetes sont encodés en base64, pas chiffrés. Utilisez Sealed Secrets ou Vault.---[Source: runbook-k8s.md - deployment]Pour déployer sur Kubernetes, utilisez kubectl apply -f deployment.yamlMéthodes utilitaires
Section intitulée « Méthodes utilitaires »Peek : aperçu rapide
Section intitulée « Peek : aperçu rapide »# Voir les premiers documents sans recherchepeek = collection.peek(limit=5)print(f"Aperçu: {peek['documents']}")Count : nombre de documents
Section intitulée « Count : nombre de documents »print(f"Total documents: {collection.count()}")Get : récupérer par ID
Section intitulée « Get : récupérer par ID »# Récupérer des documents spécifiquesdocs = collection.get(ids=["doc1", "doc2"])
# Récupérer tous les documents (avec pagination)all_docs = collection.get(limit=100, offset=0)Erreurs fréquentes
Section intitulée « Erreurs fréquentes »| Erreur | Cause | Solution |
|---|---|---|
DuplicateIDError | ID déjà existant avec add | Utilisez upsert au lieu de add |
| Mauvais résultats après rechargement | Embedding function différente | Passez la même fonction à get_collection |
InvalidCollectionException | Collection n’existe pas | Utilisez get_or_create_collection |
| Distance toujours ~2 | Embeddings incompatibles | Vérifiez que vous utilisez le même modèle |
À retenir
Section intitulée « À retenir »-
Trois modes : in-memory (dev), persistant (local), client-serveur (prod)
-
Embeddings automatiques : par défaut
all-MiniLM-L6-v2, utilisezmultilingual-e5-smallpour le français -
Upsert plutôt qu’add : évite les erreurs de doublon
-
Filtrage puissant : combine sémantique (
query_texts) + métadonnées (where) + contenu (where_document) -
Récupération cohérente : toujours passer la même
embedding_functionàget_collection