Files
confident-ai--deepeval/docs/content/integrations/vector-databases/chroma.mdx
T
2026-07-13 13:32:05 +08:00

257 lines
9.5 KiB
Plaintext

---
id: chroma
title: Chroma
sidebar_label: Chroma
---
## Quick Summary
**Chroma** is one of the most popular open-source AI application databases, and supports many retrieval features such as embeddings storage, vector search, document storage, metadata filtering, and multi-modal retrieval.
DeepEval allows you to easily evaluate and optimize your Chroma retriever by **tuning hyperparameters** like `n_results` (more commonly known as top-K) and the `embedding model` used in your Chroma retrieval pipeline.
:::caution
Chroma is not only an optional retriever you can evaluate, it is also a **required dependency** for the `deepeval.synthesizer.generate_goldens_from_docs()` method.
This method uses Chroma as its built-in backend for chunk storage and retrieval during context construction. If you plan to generate goldens from documents, make sure to install `chromadb`:
:::
:::info
To get started, install Chroma through the CLI using the following command:
```
pip install chromadb
```
:::
To learn more about using Chroma for your RAG pipeline, [visit this page](https://www.trychroma.com/). The diagram below illustrates how you can utilize Chroma as the entire retrieval pipeline for your LLM application.
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
flexDirection: "column",
}}
>
<ImageDisplayer src="https://www.trychroma.com/_next/static/media/computer.fcd1bd54.svg" />
<div
style={{
fontSize: "13px",
}}
>
Source: Chroma
</div>
</div>
## Setup Chroma
To get started with **Chroma**, initialize a persistent client and create a collection to store your documents. The collection acts as a vector database for storing and retrieving embeddings, while the persistent client ensures data is retained across sessions.
```python
import chromadb
# Initialize Chroma client
client = chromadb.PersistentClient(path="./chroma_db")
# Create or load a collection
collection = client.get_or_create_collection(name="rag_documents")
```
Next, define an **embedding model** (we'll use `sentence_transformers`) to convert document chunks into vectors before adding them to your Chroma collection, along with the document chunks as metadata.
```python
...
# Load an embedding model
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("all-MiniLM-L6-v2")
# Example document chunks
document_chunks = [
"Chroma is an open-source vector database for efficient embedding retrieval.",
"It enables fast semantic search using vector similarity.",
"Chroma retrieves relevant data with cosine similarity.",
...
]
# Store chunks with embeddings in Chroma
for i, chunk in enumerate(document_chunks):
embedding = model.encode(chunk).tolist() # Convert text to vector
collection.add(
ids=[str(i)], # Unique ID for each document
embeddings=[embedding], # Vector representation
metadatas=[{"text": chunk}] # Store original text as metadata
)
```
You'll be querying from this Chroma collection during generation to retrieve relevant contexts based on the user `input`, before passing them along with your input into your LLM's prompt template.
:::note
By default, Chroma utilizes `cosine similarity` to find similar chunks.
:::
## Evaluating Chroma Retrieval
To evaluate your Chroma retriever, you'll first need to prepare an `input` query and generate a response from your RAG pipeline in order to create an `LLMTestCase`. You'll also need to extract the contexts retrieved from your Chroma collection during generation and prepare the expected LLM response to complete the `LLMTestCase`.
:::information
By default, `input` and `actual_output` are required for all metrics. However, `retrieval_context`, `context`, and `expected_output` are optional, and different metrics may or may not require additional parameters. To check the specific requirements, [visit the metrics section](/docs/metrics-introduction).
:::
After you've prepared your `LLMTestCase`, evaluating your Chroma retriever is as easy passing the test case along with your selection of metrics into DeepEval's `evaluate` function.
### Preparing your Test Case
To prepare our test case, we'll be using `"How does Chroma work?"` as our input. Before generating a response from your RAG pipeline, you'll first need to retrieve the relevant context using a `search` function. Our `search` function in the example below first embeds the input query before retrieving the top three most relevant text chunks (`n_results=3`) from our chroma collection.
```python
...
def search(query):
query_embedding = model.encode(query).tolist()
res = collection.query(
query_embeddings=[query_embedding],
n_results=3 # Retrieve top-K matches
)
return res["metadatas"][0][0]["text"] if res["metadatas"][0] else None
query = "How does Chroma work?"
retrieval_context = search(query)
```
Next, we'll pass the retrieved context from our Chroma collection into the LLM's prompt template to generate the final response.
```python
...
prompt = """
Answer the user question based on the supporting context.
User Question:
{input}
Supporting Context:
{retrieval_context}
"""
actual_output = generate(prompt) # Replace with your LLM function
print(actual_output)
print(expected_output)
```
Printing the `actual_output` generated by our RAG pipeline yields the following example:
```
Chroma is a lightweight vector database designed for AI applications, enabling fast semantic retrieval.
```
Let's compare this to the `expected_output` we've prepared:
```
Chroma is an open-source vector database that enables fast retrieval using cosine similarity.
```
With all the elements ready, we'll create an `LLMTestCase` by providing the input and expected output, along with the actual output and retrieved context.
```python
from deepeval.test_case import LLMTestCase
...
test_case = LLMTestCase(
input=input,
actual_output=actual_output,
retrieval_context=retrieval_context,
expected_output=expected_output
)
```
### Running Evaluations
To begin running evaluations, we'll need to define metrics relevant to our Chroma retriever. These include `ContextualRecallMetric`, `ContextualPrecisionMetric`, and `ContextualRelevancyMetric`, which specifically evaluate RAG retrievers.
:::tip
To learn more about how these metrics are calculated and why they're relevant to retrievers, visit the [individual metric pages](/docs/metrics-contextual-precision).
:::
```python
from deepeval.metrics import (
ContextualPrecisionMetric,
ContextualRecallMetric,
ContextualRelevancyMetric,
)
contextual_precision = ContextualPrecisionMetric()
contextual_recall = ContextualRecallMetric(),
contextual_relevancy = ContextualRelevancyMetric()
```
To run evaluations, simply pass the prepared test case you've prepared into the `evaluate` function, along with the retriever metrics you defined.
```
from deepeval import evaluate
...
evaluate(
[test_case],
metrics=[contextual_recall, contextual_precision, contextual_relevancy]
)
```
## Improving Chroma Retrieval
Hypothetically, we've run multiple inputs and prepared several test cases, consistently observing that the `Contextual Relevancy` score is below the required threshold.
| <div style={{width: "350px"}}>Inputs</div> | <div style={{width: "250px"}}>Contextual Relevancy Score</div> | <div style={{width: "250px"}}>Contextual Recall Score</div> |
| ------------------------------------------ | -------------------------------------------------------------- | ----------------------------------------------------------- |
| "How does Chroma work?" | 0.45 | 0.85 |
| "What is the retrieval process in Chroma?" | 0.43 | 0.92 |
| "Explain Chroma's vector database." | 0.55 | 0.67 |
This suggests that you may need to adjust the length of each document or tweak `n_results` to retrieve more relevant contexts from your Chroma collection. This is because Contextual Relevancy evaluates both the **retrieved text chunks and the top-K selection**.
:::tip
If you're curious about which metrics evaluate which specific retrieval parameters, [check out this guide](/guides/guides-rag-evaluation).
:::
Depending on the failing scores in your retriever, you'll want to experiment with different parameters (e.g., `n_results`, `embedding model`, etc.) in your Chroma retrieval pipeline until you're satisfied with the results. This can be as simple as writing a for loop to run evaluations many times:
```python
...
def search(query, n_results):
query_embedding = model.encode(query).tolist()
res = collection.query(
query_embeddings=[query_embedding],
n_results=n_results # Retrieve top-K matches
)
return res["metadatas"][0][0]["text"] if res["metadatas"][0] else None
# Define input and expected output
...
# Iterate over different top-K values
for top_k in [3, 5, 7]:
retrieval_context = search(input_query, top_k)
# Define test case
...
# Evaluate the retrieval quality
evaluate(
[test_case],
metrics=[contextual_recall, contextual_precision, contextual_relevancy]
)
```
:::note
If you need a systematic way to analyze your retriever and compare the effects of changing chroma hyperparameters side by side, you'll want to [log in to Confident AI](https://www.confident-ai.com/).
:::