From c205d58b7e580e3d62cc78f77462244e07fb00df Mon Sep 17 00:00:00 2001 From: Martin Breuss Date: Tue, 15 Sep 2026 17:02:19 +0000 Subject: [PATCH 1/2] Update ChromaDB tutorial materials for ChromaDB 1.5 and openai 3.x - Pin all dependencies to the tested versions (Python 3.12+) - Use configuration={"hnsw": ...} instead of metadata hnsw:space - Fix off-by-one that dropped the last document of every batch and read the batch size from client.get_max_batch_size() - Use itertools.batched() instead of more-itertools - Load the collection from its persisted embedding function config - Polars: schema_overrides= and maintain_order=True - Move the OpenAI code to the OpenAI() client and Responses API, with the API key loaded from .env via python-dotenv - Use the spaCy large model, since the 3.8 medium model prunes vectors Co-Authored-By: Claude Fable 5.1 --- .../README.md | 15 ++- .../car_data_etl.py | 4 +- .../chroma_utils.py | 7 +- .../config.json | 3 - .../create_car_review_collection.py | 10 +- .../llm_car_review_context.py | 90 ++++++----------- .../requirements.txt | 99 ++----------------- .../word_vectors.py | 2 +- 8 files changed, 56 insertions(+), 174 deletions(-) delete mode 100644 embeddings-and-vector-databases-with-chromadb/config.json diff --git a/embeddings-and-vector-databases-with-chromadb/README.md b/embeddings-and-vector-databases-with-chromadb/README.md index ee0d1636d0..f93aaad648 100644 --- a/embeddings-and-vector-databases-with-chromadb/README.md +++ b/embeddings-and-vector-databases-with-chromadb/README.md @@ -1,11 +1,18 @@ -# Embeddings and Vector Databases With ChromaDB +# ChromaDB: Embeddings and Vector Databases in Python -Supporting code for the Real Python tutorial [Embeddings and Vector Databases With ChromaDB](https://realpython.com/chromadb-vector-database/). +Supporting code for the Real Python tutorial [ChromaDB: Embeddings and Vector Databases in Python](https://realpython.com/chromadb-vector-database/). -To run the code in this tutorial, you should have `numpy`, `spacy`, `sentence-transformers`, `chromadb`, `polars`, `more-itertools`, and `openai` installed in your environment. +The code was tested with Python 3.14 and the pinned versions in `requirements.txt`. You need Python 3.12 or later. -You can install the dependencies manually, or by running: +You can install the dependencies by running: ``` (venv) $ python -m pip install -r requirements.txt +(venv) $ python -m spacy download en_core_web_lg +``` + +To run the LLM examples, store your OpenAI API key in a `.env` file in this directory: + +``` +OPENAI_API_KEY="" ``` diff --git a/embeddings-and-vector-databases-with-chromadb/car_data_etl.py b/embeddings-and-vector-databases-with-chromadb/car_data_etl.py index 3f8fdb171b..92bd5b34ee 100644 --- a/embeddings-and-vector-databases-with-chromadb/car_data_etl.py +++ b/embeddings-and-vector-databases-with-chromadb/car_data_etl.py @@ -20,7 +20,7 @@ def prepare_car_reviews_data( } # Scan the car reviews dataset(s) - car_reviews = pl.scan_csv(data_path, dtypes=dtypes) + car_reviews = pl.scan_csv(data_path, schema_overrides=dtypes) # Extract the vehicle title and year as new columns # Filter on selected years @@ -48,7 +48,7 @@ def prepare_car_reviews_data( "Vehicle_Model", ] ) - .sort(["Vehicle_Model", "Rating"]) + .sort(["Vehicle_Model", "Rating"], maintain_order=True) .collect() ) diff --git a/embeddings-and-vector-databases-with-chromadb/chroma_utils.py b/embeddings-and-vector-databases-with-chromadb/chroma_utils.py index 253c191a1f..0178202717 100644 --- a/embeddings-and-vector-databases-with-chromadb/chroma_utils.py +++ b/embeddings-and-vector-databases-with-chromadb/chroma_utils.py @@ -25,14 +25,15 @@ def build_chroma_collection( collection = chroma_client.create_collection( name=collection_name, embedding_function=embedding_func, - metadata={"hnsw:space": distance_func_name}, + configuration={"hnsw": {"space": distance_func_name}}, ) + batch_size = chroma_client.get_max_batch_size() document_indices = list(range(len(documents))) - for batch in batched(document_indices, 166): + for batch in batched(document_indices, batch_size): start_idx = batch[0] - end_idx = batch[-1] + end_idx = batch[-1] + 1 collection.add( ids=ids[start_idx:end_idx], diff --git a/embeddings-and-vector-databases-with-chromadb/config.json b/embeddings-and-vector-databases-with-chromadb/config.json deleted file mode 100644 index a395e21fcf..0000000000 --- a/embeddings-and-vector-databases-with-chromadb/config.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "openai-secret-key": "your-api-key" -} \ No newline at end of file diff --git a/embeddings-and-vector-databases-with-chromadb/create_car_review_collection.py b/embeddings-and-vector-databases-with-chromadb/create_car_review_collection.py index 3c57f49cbc..49a3671e5e 100644 --- a/embeddings-and-vector-databases-with-chromadb/create_car_review_collection.py +++ b/embeddings-and-vector-databases-with-chromadb/create_car_review_collection.py @@ -1,7 +1,6 @@ import chromadb from car_data_etl import prepare_car_reviews_data from chroma_utils import build_chroma_collection -from chromadb.utils import embedding_functions DATA_PATH = "data/archive/*" CHROMA_PATH = "car_review_embeddings" @@ -20,12 +19,9 @@ ) client = chromadb.PersistentClient(CHROMA_PATH) -embedding_func = embedding_functions.SentenceTransformerEmbeddingFunction( - model_name=EMBEDDING_FUNC_NAME -) -collection = client.get_collection( - name=COLLECTION_NAME, embedding_function=embedding_func -) +collection = client.get_collection(name=COLLECTION_NAME) + +print(collection.count()) great_reviews = collection.query( query_texts=[ diff --git a/embeddings-and-vector-databases-with-chromadb/llm_car_review_context.py b/embeddings-and-vector-databases-with-chromadb/llm_car_review_context.py index cc9bff4112..3ec79a885a 100644 --- a/embeddings-and-vector-databases-with-chromadb/llm_car_review_context.py +++ b/embeddings-and-vector-databases-with-chromadb/llm_car_review_context.py @@ -1,41 +1,31 @@ -import json import os import chromadb -import openai -from chromadb.utils import embedding_functions +from dotenv import load_dotenv +from openai import OpenAI os.environ["TOKENIZERS_PARALLELISM"] = "false" -DATA_PATH = "data/archive/*" CHROMA_PATH = "car_review_embeddings" -EMBEDDING_FUNC_NAME = "multi-qa-MiniLM-L6-cos-v1" COLLECTION_NAME = "car_reviews" +MODEL = "gpt-5.6-luna" -with open("config.json", "r") as json_file: - config_data = json.load(json_file) +load_dotenv() -openai.api_key = config_data.get("openai-secret-key") - -client = chromadb.PersistentClient(CHROMA_PATH) -embedding_func = embedding_functions.SentenceTransformerEmbeddingFunction( - model_name=EMBEDDING_FUNC_NAME -) - -collection = client.get_collection( - name=COLLECTION_NAME, embedding_function=embedding_func -) +openai_client = OpenAI() +chroma_client = chromadb.PersistentClient(CHROMA_PATH) +collection = chroma_client.get_collection(name=COLLECTION_NAME) context = """ - You are a customer success employee at a large - car dealership. Use the following car reviews - to answer questions: {} - """ +You are a customer success employee at a large + car dealership. Use the following car reviews + to answer questions: {} +""" question = """ - What's the key to great customer satisfaction - based on detailed positive reviews? - """ +What's the key to great customer satisfaction + based on detailed positive reviews? +""" good_reviews = collection.query( query_texts=[question], @@ -46,45 +36,25 @@ reviews_str = ",".join(good_reviews["documents"][0]) -good_review_summaries = openai.ChatCompletion.create( - model="gpt-3.5-turbo", - messages=[ - {"role": "system", "content": context.format(reviews_str)}, - {"role": "user", "content": question}, - ], - temperature=0, - n=1, -) - -reviews_str = ",".join(good_reviews["documents"][0]) - print("Good reviews: ") print(reviews_str) print("###########################################") -good_review_summaries = openai.ChatCompletion.create( - model="gpt-3.5-turbo", - messages=[ - {"role": "system", "content": context.format(reviews_str)}, - {"role": "user", "content": question}, - ], - temperature=0, - n=1, +good_review_summaries = openai_client.responses.create( + model=MODEL, + instructions=context.format(reviews_str), + input=question, ) print("AI-Generated summary of good reviews: ") -print(good_review_summaries["choices"][0]["message"]["content"]) +print(good_review_summaries.output_text) print("###########################################") - -context = """ - You are a customer success employee at a large car dealership. - Use the following car reivews to answer questions: {} - """ question = """ - Which of these poor reviews has the worst implications about - our dealership? Explain why. - """ +Which of these poor reviews has the + worst implications about our dealership? + Explain why. +""" poor_reviews = collection.query( query_texts=[question], @@ -99,16 +69,12 @@ print(poor_reviews["documents"][0][0]) print("###########################################") -poor_review_analysis = openai.ChatCompletion.create( - model="gpt-3.5-turbo", - messages=[ - {"role": "system", "content": context.format(reviews_str)}, - {"role": "user", "content": question}, - ], - temperature=0, - n=1, +poor_review_analysis = openai_client.responses.create( + model=MODEL, + instructions=context.format(reviews_str), + input=question, ) print("AI-Generated summary of the single worst review: ") -print(poor_review_analysis["choices"][0]["message"]["content"]) +print(poor_review_analysis.output_text) print("###########################################") diff --git a/embeddings-and-vector-databases-with-chromadb/requirements.txt b/embeddings-and-vector-databases-with-chromadb/requirements.txt index 48d2e1ed1c..aff0a72851 100644 --- a/embeddings-and-vector-databases-with-chromadb/requirements.txt +++ b/embeddings-and-vector-databases-with-chromadb/requirements.txt @@ -1,92 +1,7 @@ -aiohttp==3.8.6 -aiosignal==1.3.1 -annotated-types==0.6.0 -anyio==3.7.1 -async-timeout==4.0.3 -attrs==23.1.0 -backoff==2.2.1 -bcrypt==4.0.1 -blis==0.7.11 -catalogue==2.0.10 -certifi==2023.7.22 -charset-normalizer==3.3.0 -chroma-hnswlib==0.7.3 -chromadb==0.4.14 -click==8.1.7 -cloudpathlib==0.16.0 -coloredlogs==15.0.1 -confection==0.1.3 -cymem==2.0.8 -fastapi==0.104.0 -filelock==3.12.4 -flatbuffers==23.5.26 -frozenlist==1.4.0 -fsspec==2023.9.2 -grpcio==1.59.0 -h11==0.14.0 -httptools==0.6.1 -huggingface-hub==0.17.3 -humanfriendly==10.0 -idna==3.4 -importlib-resources==6.1.0 -Jinja2==3.1.2 -joblib==1.3.2 -langcodes==3.3.0 -MarkupSafe==2.1.3 -monotonic==1.6 -more-itertools==10.1.0 -mpmath==1.3.0 -multidict==6.0.4 -murmurhash==1.0.10 -networkx==3.2 -nltk==3.8.1 -numpy==1.26.1 -onnxruntime==1.16.1 -openai==0.28.1 -overrides==7.4.0 -packaging==23.2 -Pillow==10.1.0 -polars==0.19.9 -posthog==3.0.2 -preshed==3.0.9 -protobuf==4.24.4 -pulsar-client==3.3.0 -pydantic==2.4.2 -pydantic_core==2.10.1 -PyPika==0.48.9 -python-dateutil==2.8.2 -python-dotenv==1.0.0 -PyYAML==6.0.1 -regex==2023.10.3 -requests==2.31.0 -safetensors==0.4.0 -scikit-learn==1.3.1 -scipy==1.11.3 -sentence-transformers==2.2.2 -sentencepiece==0.1.99 -six==1.16.0 -smart-open==6.4.0 -sniffio==1.3.0 -spacy==3.7.2 -spacy-legacy==3.0.12 -spacy-loggers==1.0.5 -srsly==2.4.8 -starlette==0.27.0 -sympy==1.12 -thinc==8.2.1 -threadpoolctl==3.2.0 -tokenizers==0.14.1 -torch==2.1.0 -torchvision==0.16.0 -tqdm==4.66.1 -transformers==4.34.1 -typer==0.9.0 -typing_extensions==4.8.0 -urllib3==2.0.7 -uvicorn==0.23.2 -uvloop==0.18.0 -wasabi==1.1.2 -watchfiles==0.21.0 -weasel==0.3.3 -websockets==11.0.3 -yarl==1.9.2 +chromadb==1.5.9 +numpy==2.5.3 +openai==3.14.0 +polars==1.44.2 +python-dotenv==1.2.3 +sentence-transformers==6.0.1 +spacy==3.8.16 diff --git a/embeddings-and-vector-databases-with-chromadb/word_vectors.py b/embeddings-and-vector-databases-with-chromadb/word_vectors.py index ae91ddd637..8a731fcdb6 100644 --- a/embeddings-and-vector-databases-with-chromadb/word_vectors.py +++ b/embeddings-and-vector-databases-with-chromadb/word_vectors.py @@ -3,7 +3,7 @@ import spacy # Load the medium-size English model -nlp = spacy.load("en_core_web_md") +nlp = spacy.load("en_core_web_lg") # Get the word vector for the word "dog" dog_embedding = nlp.vocab["dog"].vector From 7381cc3c6139952e283f2bddb8a016b1651de350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20Zaczy=C5=84ski?= Date: Sun, 20 Sep 2026 12:00:56 +0000 Subject: [PATCH 2/2] Fix Final QA findings in the ChromaDB update materials - chroma_utils.py: import batched from itertools, not more_itertools. more-itertools is not in requirements.txt, so the script raised ImportError for anyone following the README. The tutorial uses the stdlib version, which the PR description already claimed. - car_data_etl.py: rename Vehicle_Model to Vehicle_Make. Index 1 of a title like "2017 Volvo XC90 ..." is the make, and the tutorial documents the metadata key as Vehicle_Make, so the collection built from this script had a different key than the article shows. - README.md: use the house (.venv) prompts and pin the spaCy model to en_core_web_lg-3.8.0, matching the tutorial's install commands. Co-Authored-By: Claude Opus 5 (1M context) --- embeddings-and-vector-databases-with-chromadb/README.md | 4 ++-- .../car_data_etl.py | 8 ++++---- .../chroma_utils.py | 2 +- uv.lock | 3 +++ 4 files changed, 10 insertions(+), 7 deletions(-) create mode 100644 uv.lock diff --git a/embeddings-and-vector-databases-with-chromadb/README.md b/embeddings-and-vector-databases-with-chromadb/README.md index f93aaad648..54d3718467 100644 --- a/embeddings-and-vector-databases-with-chromadb/README.md +++ b/embeddings-and-vector-databases-with-chromadb/README.md @@ -7,8 +7,8 @@ The code was tested with Python 3.14 and the pinned versions in `requirements.tx You can install the dependencies by running: ``` -(venv) $ python -m pip install -r requirements.txt -(venv) $ python -m spacy download en_core_web_lg +(.venv) $ python -m pip install -r requirements.txt +(.venv) $ python -m spacy download en_core_web_lg-3.8.0 --direct ``` To run the LLM examples, store your OpenAI API key in a `.env` file in this directory: diff --git a/embeddings-and-vector-databases-with-chromadb/car_data_etl.py b/embeddings-and-vector-databases-with-chromadb/car_data_etl.py index 92bd5b34ee..f5795c94f7 100644 --- a/embeddings-and-vector-databases-with-chromadb/car_data_etl.py +++ b/embeddings-and-vector-databases-with-chromadb/car_data_etl.py @@ -22,7 +22,7 @@ def prepare_car_reviews_data( # Scan the car reviews dataset(s) car_reviews = pl.scan_csv(data_path, schema_overrides=dtypes) - # Extract the vehicle title and year as new columns + # Extract the vehicle year and make as new columns # Filter on selected years car_review_db_data = ( car_reviews.with_columns( @@ -34,7 +34,7 @@ def prepare_car_reviews_data( .cast(pl.Int64) ).alias("Vehicle_Year"), (pl.col("Vehicle_Title").str.split(by=" ").list.get(1)).alias( - "Vehicle_Model" + "Vehicle_Make" ), ] ) @@ -45,10 +45,10 @@ def prepare_car_reviews_data( "Review", "Rating", "Vehicle_Year", - "Vehicle_Model", + "Vehicle_Make", ] ) - .sort(["Vehicle_Model", "Rating"], maintain_order=True) + .sort(["Vehicle_Make", "Rating"], maintain_order=True) .collect() ) diff --git a/embeddings-and-vector-databases-with-chromadb/chroma_utils.py b/embeddings-and-vector-databases-with-chromadb/chroma_utils.py index 0178202717..016026c819 100644 --- a/embeddings-and-vector-databases-with-chromadb/chroma_utils.py +++ b/embeddings-and-vector-databases-with-chromadb/chroma_utils.py @@ -1,8 +1,8 @@ import pathlib +from itertools import batched import chromadb from chromadb.utils import embedding_functions -from more_itertools import batched def build_chroma_collection( diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000000..a5bc51476b --- /dev/null +++ b/uv.lock @@ -0,0 +1,3 @@ +version = 1 +revision = 3 +requires-python = ">=3.14"