Chroma : base vectorielle locale simple et rapide

tl;dr: Chroma est la base vectorielle la plus simple : `pip install chromadb` et c'est parti. 3 modes (in-memory, persistent, client-server), intégration LangChain native. Idéal dev/prototypes, limité pour production grande échelle.

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.

Diagramme technique illustrant Chroma DB, base de données vectorielle open-source pour les bases de données vectorielles utilisées en IA

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 chromadb et 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
💡 Idéal pour : Prototypes, MVPs, développement local, apprentissage, petites applications (<100K vecteurs).

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")
💡 Embeddings automatiques : Chroma génère les embeddings automatiquement ! Pas besoin de les calculer manuellement.

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
)
🔎 Tip
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érationLatenceNotes
Add100ms/batchBatch 100 docs
Query50-200msSelon taille collection
In-memory10-50msLe plus rapide
Persistent50-200msLecture 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
⚠️ Warning
⚠️ Règle : Chroma pour dev/prototypes. Migrez vers Pinecone/Weaviate/Qdrant pour production à échelle.

Best practices

✅ À faire

  1. Mode persistent pour dev
client = chromadb.PersistentClient(path="./db")
  1. Batch add pour performance
# Batch de 100-500 documents
collection.add(documents=batch, ids=ids)
  1. Filtres pour affiner
where={"category": "tech", "views": {"$gte": 1000}}
  1. get_or_create pour collections
collection = client.get_or_create_collection("my_col")

❌ À éviter

  1. In-memory en production : Données perdues au reboot

  2. Pas de batch : Add un par un = très lent

  3. 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

  1. Apprendre : Commencez avec Chroma
  2. Prototyper : Validez votre idée
  3. 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 :