Chroma : base vectorielle locale simple et rapide
Chroma est la base de données vectorielle la plus simple à utiliser. Installation en une ligne, API intuitive, parfaite pour démarrer.
Si vous débutez avec les bases vectorielles ou voulez un prototype rapide, commencez par Chroma.

Objectifs de l’article
Après avoir lu cet article, vous serez capable de :
- ✅ Installer Chroma en 30 secondes
- ✅ Utiliser les 3 modes (in-memory, persistent, client-server)
- ✅ Créer collections et effectuer CRUD
- ✅ Utiliser embeddings automatiques
- ✅ Intégrer avec LangChain (natif)
- ✅ Comprendre quand utiliser Chroma vs alternatives
- ✅ Migrer vers production (Pinecone, Weaviate)
Présentation de Chroma
Qu’est-ce que Chroma ?
Chroma est une base vectorielle open source créée pour la simplicité. Tagline : “The AI-native open-source embedding database”.
Points forts :
- 🚀 Installation :
pip install chromadbet c’est tout - 📦 Embedded : Pas de serveur à gérer
- 🔗 LangChain : Intégration native
- 🆓 Gratuit : 100% open source
- 🐍 Python-first : API très pythonic
Avantages
- ✅ Simplicité extrême (meilleure DX)
- ✅ Zéro configuration pour commencer
- ✅ Embeddings automatiques (comme Weaviate)
- ✅ Modes flexibles (memory, disk, server)
- ✅ Parfait pour prototypes et développement local
Inconvénients
- ❌ Performance limitée (>1M vecteurs)
- ❌ Pas de features avancées (hybrid search, etc.)
- ❌ Scaling limité (single-node essentiellement)
- ❌ Pas adapté production grande échelle
Installation
La plus simple du monde
pip install chromadb
C’est tout ! Aucune configuration, aucun serveur à lancer.
Vérification
import chromadb
print(chromadb.__version__) # Ex: 0.4.20
Les 3 modes de Chroma
Chroma offre 3 modes selon vos besoins.
In-Memory (Par Défaut)
Données en RAM. Parfait pour tests rapides.
import chromadb
# Client in-memory
client = chromadb.Client()
# Créer collection
collection = client.create_collection("test")
# Ajouter données
collection.add(
documents=["Doc 1", "Doc 2"],
ids=["id1", "id2"]
)
# Rechercher
results = collection.query(
query_texts=["recherche"],
n_results=2
)
print(results)
Caractéristiques :
- ✅ Très rapide (RAM)
- ✅ Pas de fichiers
- ❌ Données perdues à la fin du script
Use case : Tests unitaires, expérimentations rapides.
Persistent (Stockage Disque)
Données sauvegardées sur disque.
import chromadb
# Client persistent
client = chromadb.PersistentClient(path="./chroma_db")
# Créer/récupérer collection
collection = client.get_or_create_collection("my_collection")
# Ajouter données
collection.add(
documents=["Doc 1", "Doc 2"],
ids=["id1", "id2"]
)
print("Données sauvegardées dans ./chroma_db/")
Caractéristiques :
- ✅ Données persistées
- ✅ Rechargement automatique
- ✅ Adapté dev local
Use case : Développement local, prototypes avec persistance.
Client-Server
Chroma comme serveur dédié.
Lancer le Serveur
# Installation serveur
pip install chromadb-server
# Lancer (port 8000 par défaut)
chroma run --path ./chroma_data
Ou avec Docker :
docker run -p 8000:8000 chromadb/chroma
Client Python
import chromadb
# Se connecter au serveur
client = chromadb.HttpClient(host="localhost", port=8000)
# Utilisation identique
collection = client.get_or_create_collection("my_collection")
Caractéristiques :
- ✅ Architecture client-server
- ✅ Multi-clients simultanés
- ✅ Plus proche production
Use case : Équipe, environnement staging, petite production.
Collections
Créer une collection
import chromadb
client = chromadb.Client()
# Créer
collection = client.create_collection(
name="articles",
metadata={"description": "Articles de blog"}
)
print(f"Collection '{collection.name}' créée")
Lister collections
collections = client.list_collections()
for col in collections:
print(f"- {col.name}")
Récupérer collection existante
# get : erreur si n'existe pas
collection = client.get_collection("articles")
# get_or_create : crée si n'existe pas
collection = client.get_or_create_collection("articles")
Supprimer collection
client.delete_collection("articles")
CRUD operations
Add (Insert)
# Données
documents = [
"Les bases de données vectorielles sont essentielles pour l'IA moderne.",
"Chroma est la base vectorielle la plus simple à utiliser.",
"Le RAG améliore les LLMs en leur donnant des connaissances externes."
]
# Métadonnées
metadatas = [
{"category": "tech", "views": 1250},
{"category": "tech", "views": 890},
{"category": "ai", "views": 2100}
]
# IDs
ids = ["doc1", "doc2", "doc3"]
# Ajouter
collection.add(
documents=documents,
metadatas=metadatas,
ids=ids
)
print(f"{len(documents)} documents ajoutés")
Add avec embeddings manuels
Si vous voulez utiliser vos propres embeddings :
from sentence_transformers import SentenceTransformer
# Générer embeddings
model = SentenceTransformer('all-MiniLM-L6-v2')
embeddings = model.encode(documents).tolist()
# Ajouter avec embeddings
collection.add(
documents=documents,
embeddings=embeddings, # Vos embeddings
metadatas=metadatas,
ids=ids
)
Query (Recherche)
# Recherche simple
results = collection.query(
query_texts=["bases de données"],
n_results=2
)
# Afficher
for i, doc in enumerate(results['documents'][0]):
print(f"{i+1}. {doc[:50]}...")
print(f" Distance: {results['distances'][0][i]:.4f}")
print()
Output :
1. Les bases de données vectorielles sont essentielles...
Distance: 0.2341
2. Chroma est la base vectorielle la plus simple...
Distance: 0.4567
Query avec Filtres
# Filtrer par métadonnées
results = collection.query(
query_texts=["intelligence artificielle"],
n_results=5,
where={"category": "ai"} # Filtre
)
# Filtre numérique
results = collection.query(
query_texts=["technologie"],
n_results=5,
where={"views": {"$gte": 1000}} # >= 1000 vues
)
# Filtre complexe (AND)
results = collection.query(
query_texts=["IA"],
n_results=5,
where={
"$and": [
{"category": "tech"},
{"views": {"$gte": 1000}}
]
}
)
Get (récupérer par ID)
# Récupérer documents spécifiques
results = collection.get(
ids=["doc1", "doc2"],
include=["documents", "metadatas"]
)
for id, doc in zip(results['ids'], results['documents']):
print(f"{id}: {doc[:50]}...")
Update
# Mettre à jour
collection.update(
ids=["doc1"],
metadatas=[{"category": "tech", "views": 2000}] # Nouvelles métadonnées
)
Upsert
# Insert si nouveau, Update si existe
collection.upsert(
ids=["doc4"],
documents=["Nouveau document"],
metadatas=[{"category": "news", "views": 0}]
)
Delete
# Supprimer par ID
collection.delete(ids=["doc1", "doc2"])
# Supprimer par filtre
collection.delete(where={"category": "obsolete"})
# Supprimer tout
collection.delete() # Vide la collection
Embeddings automatiques
Chroma peut générer automatiquement les embeddings.
Modèles d’embedding
# Par défaut : all-MiniLM-L6-v2 (Sentence-BERT)
collection = client.create_collection(
name="auto_embed",
metadata={"hnsw:space": "cosine"} # Métrique similarité
)
# Spécifier un autre modèle
from chromadb.utils import embedding_functions
# Sentence-BERT custom
sentence_transformer_ef = embedding_functions.SentenceTransformerEmbeddingFunction(
model_name="all-mpnet-base-v2"
)
collection = client.create_collection(
name="custom_embed",
embedding_function=sentence_transformer_ef
)
# OpenAI embeddings
openai_ef = embedding_functions.OpenAIEmbeddingFunction(
api_key="your-openai-key",
model_name="text-embedding-3-small"
)
collection = client.create_collection(
name="openai_embed",
embedding_function=openai_ef
)
Recommandation : Le modèle par défaut (
all-MiniLM-L6-v2) est suffisant pour la plupart des cas. Utilisez OpenAI si vous avez besoin de qualité maximale.Intégration LangChain
Chroma a une intégration native avec LangChain.
Installation
pip install langchain langchain-chroma
Code
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain.schema import Document
# Embeddings
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# Vectorstore
vectorstore = Chroma(
collection_name="langchain_collection",
embedding_function=embeddings,
persist_directory="./chroma_langchain" # Persistance
)
# Ajouter documents
docs = [
Document(
page_content="Les bases vectorielles sont essentielles.",
metadata={"source": "doc1", "category": "tech"}
),
Document(
page_content="Chroma est très simple à utiliser.",
metadata={"source": "doc2", "category": "tech"}
)
]
vectorstore.add_documents(docs)
# Recherche
results = vectorstore.similarity_search("bases de données", k=2)
for doc in results:
print(f"- {doc.page_content[:50]}...")
print(f" Source: {doc.metadata['source']}")
RAG avec LangChain + Chroma
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.chains import RetrievalQA
# 1. Vectorstore
embeddings = OpenAIEmbeddings()
vectorstore = Chroma(
persist_directory="./chroma_db",
embedding_function=embeddings
)
# 2. Retriever
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
# 3. LLM
llm = ChatOpenAI(model="gpt-4", temperature=0)
# 4. Chain RAG
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever,
return_source_documents=True
)
# 5. Poser question
question = "Qu'est-ce qu'une base vectorielle ?"
result = qa_chain({"query": question})
print(f"Question: {question}")
print(f"Réponse: {result['result']}")
print(f"\nSources: {len(result['source_documents'])} documents")
Exemple RAG complet
import chromadb
from chromadb.utils import embedding_functions
from openai import OpenAI
class ChromaRAG:
"""Simple RAG avec Chroma."""
def __init__(self, persist_path: str = "./chroma_rag"):
# Chroma
self.client = chromadb.PersistentClient(path=persist_path)
# Embedding function (OpenAI)
self.embed_fn = embedding_functions.OpenAIEmbeddingFunction(
api_key="your-openai-key",
model_name="text-embedding-3-small"
)
# Collection
self.collection = self.client.get_or_create_collection(
name="knowledge_base",
embedding_function=self.embed_fn
)
# OpenAI LLM
self.llm = OpenAI(api_key="your-openai-key")
def index_documents(self, documents: list[dict]):
"""
Indexer documents.
Args:
documents: Liste de {'id', 'text', 'metadata'}
"""
self.collection.add(
ids=[doc['id'] for doc in documents],
documents=[doc['text'] for doc in documents],
metadatas=[doc['metadata'] for doc in documents]
)
print(f"{len(documents)} documents indexés")
def ask(self, question: str, n_results: int = 3) -> dict:
"""
Poser une question.
Returns:
{'answer', 'sources'}
"""
# 1. Rechercher
results = self.collection.query(
query_texts=[question],
n_results=n_results
)
# 2. Contexte
contexts = results['documents'][0]
context = "\n\n".join(contexts)
# 3. Générer
response = self.llm.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "Réponds avec le contexte fourni."},
{"role": "user", "content": f"Contexte:\n{context}\n\nQuestion: {question}"}
]
)
answer = response.choices[0].message.content
return {
'answer': answer,
'sources': contexts
}
# === Utilisation ===
# Init
rag = ChromaRAG()
# Indexer
docs = [
{
'id': 'doc1',
'text': 'Chroma est une base vectorielle simple et efficace.',
'metadata': {'category': 'tech', 'date': '2025-01-15'}
},
{
'id': 'doc2',
'text': 'Les bases vectorielles utilisent des embeddings pour la recherche sémantique.',
'metadata': {'category': 'tech', 'date': '2025-01-16'}
}
]
rag.index_documents(docs)
# Poser question
result = rag.ask("Qu'est-ce que Chroma ?")
print(f"Réponse: {result['answer']}")
Quand utiliser Chroma ?
✅ Utiliser Chroma si
- Prototype/MVP rapide
- Développement local
- Apprentissage (découvrir les bases vectorielles)
- <100K vecteurs
- Application simple (pas de besoins avancés)
- Pas d’équipe DevOps
❌ Ne PAS utiliser Chroma si
- Production grande échelle (>1M vecteurs)
- Hybrid search requis
- Haute disponibilité critique
- Performance extrême requise
- Scaling horizontal nécessaire
Migration vers production
Quand votre prototype Chroma fonctionne, migrez vers :
Pinecone
# De Chroma...
collection.add(documents=docs, ids=ids)
# ...vers Pinecone
from pinecone import Pinecone
pc = Pinecone(api_key="...")
index = pc.Index("production")
# Générer embeddings
embeddings = model.encode(docs)
# Upsert
index.upsert(vectors=[
{"id": id, "values": emb, "metadata": {"text": doc}}
for id, emb, doc in zip(ids, embeddings, docs)
])
Weaviate
# De Chroma...
collection.add(documents=docs, ids=ids)
# ...vers Weaviate
import weaviate
client = weaviate.Client("http://localhost:8080")
with client.batch as batch:
for id, doc in zip(ids, docs):
batch.add_data_object(
data_object={"content": doc},
class_name="Document",
uuid=id
)
Qdrant
# De Chroma...
collection.add(documents=docs, ids=ids)
# ...vers Qdrant
from qdrant_client import QdrantClient
client = QdrantClient("localhost", port=6333)
# Créer collection
client.create_collection(
collection_name="documents",
vectors_config={"size": 384, "distance": "Cosine"}
)
# Upsert
embeddings = model.encode(docs)
client.upsert(
collection_name="documents",
points=[
{"id": id, "vector": emb.tolist(), "payload": {"text": doc}}
for id, emb, doc in zip(ids, embeddings, docs)
]
)
Performance et limitations
Benchmarks
Dataset : 100K vecteurs, 384 dimensions
| Opération | Latence | Notes |
|---|---|---|
| Add | 100ms/batch | Batch 100 docs |
| Query | 50-200ms | Selon taille collection |
| In-memory | 10-50ms | Le plus rapide |
| Persistent | 50-200ms | Lecture disque |
Limites
- Scaling : Performance dégrade >500K-1M vecteurs
- Single-node : Pas de distribution native
- Features : Pas de hybrid search, filtres limités
- Production : Moins mature que Pinecone/Weaviate
⚠️ Règle : Chroma pour dev/prototypes. Migrez vers Pinecone/Weaviate/Qdrant pour production à échelle.
Best practices
✅ À faire
- Mode persistent pour dev
client = chromadb.PersistentClient(path="./db")
- Batch add pour performance
# Batch de 100-500 documents
collection.add(documents=batch, ids=ids)
- Filtres pour affiner
where={"category": "tech", "views": {"$gte": 1000}}
- get_or_create pour collections
collection = client.get_or_create_collection("my_col")
❌ À éviter
In-memory en production : Données perdues au reboot
Pas de batch : Add un par un = très lent
Trop de vecteurs : >500K = considérer alternative
Conclusion
Chroma est parfait pour démarrer rapidement avec les bases vectorielles.
Points clés
✅ Simplicité : Installation en 1 ligne, API intuitive ✅ Embeddings auto : Pas besoin de les gérer ✅ LangChain : Intégration native ✅ Gratuit : 100% open source ✅ Flexible : 3 modes (memory, disk, server)
Progression recommandée
- Apprendre : Commencez avec Chroma
- Prototyper : Validez votre idée
- Scaler : Migrez vers Pinecone/Weaviate/Qdrant
Dans le prochain article, nous comparerons toutes les solutions (Qdrant, Milvus, FAISS, pgvector) avec un tableau décisionnel complet.
👉 Article 7 : Comparatif Complet des Solutions
Exercices pratiques
Premier RAG
Créez un chatbot RAG avec Chroma + OpenAI en <50 lignes.
Comparer modes
Benchmarkez les 3 modes (memory, persistent, server) sur 10K documents.
Migration
Implémentez une fonction pour migrer de Chroma vers Pinecone.
Ressources complémentaires
Articles liés :
Documentation :