liveBook · Manning

Chroma DB

As explained in Grokking AI Applications

Chroma is an open-source vector database for storing embeddings and associated data and performing similarity-based retrieval.

Chroma DB is a local vector database for a retrieval-augmented generation (RAG) system. It stores embedded document chunks, groups them into collections, and returns chunks similar to a query. In a Langflow workflow, it forms the bridge between document ingestion and answer generation. section 4.2

A practical Chroma workflow has these stages:

  • Split source documents into manageable, partly overlapping chunks so retrieval can preserve useful context. section 4.2
  • Connect the chunks to Chroma's ingestion input and assign them to a named collection, such as menu. section 4.2
  • Set a persist directory, such as menu, to keep the local vector database on disk. section 4.2
  • Retrieve the top matching chunks, concatenate them, and pass them as guarded context to a language model. section 4.4

A pizza-menu assistant

A RAG assistant can load a pizzeria menu PDF, split its text, embed the chunks, and store them in a Chroma collection named menu. When someone asks about a pizza or wine pairing, Chroma retrieves relevant menu entries for the answer-generation step. section 4.2 section 4.4

"""
Install dependencies once:

   pip install pypdf chromadb langchain-openai langchain-community \
       langchain-text-splitters python-dotenv

"""

import os
from pathlib import Path

from dotenv import load_dotenv
from langchain_openai import ChatOpenAI, OpenAIEmbeddings    #A
from langchain_community.vectorstores import Chroma    #B
from langchain_community.document_loaders import PyPDFLoader    #C
from langchain_text_splitters import RecursiveCharacterTextSplitter    #D
from langchain_core.prompts import PromptTemplate    #E

BASE_DIR = Path(__file__).resolve().parent
MENU_PDF = BASE_DIR / "Lu Sule Pizzeria - Info and Menu.pdf"
INDEX_DIR = BASE_DIR / "menu"
COLLECTION_NAME = "menu"

load_dotenv()
# os.environ["OPENAI_API_KEY"] = "REPLACE_WITH_YOUR_KEY"

def ensure_vectorstore(pdf_path: Path, index_dir: Path) - > Chroma:
   """Load or build the Chroma collection mirroring Langflow's ingestion."""

   embeddings = OpenAIEmbeddings()

   if index_dir.exists():
       return Chroma(
           collection_name=COLLECTION_NAME,
           embedding_function=embeddings,
           persist_directory=str(index_dir),
       )

   loader = PyPDFLoader(str(pdf_path))
   docs = loader.load()
   splitter = RecursiveCharacterTextSplitter(chunk_size=400, chunk_overlap=150)
   chunks = splitter.split_documents(docs)
   vectorstore = Chroma.from_documents(
       documents=chunks,
       embedding=embeddings,
       collection_name=COLLECTION_NAME,
       persist_directory=str(index_dir),
   )
   return vectorstore

def build_prompt() - > PromptTemplate
   """Context-aware RAG prompt identical to the Langflow PromptTemplate."""

   return PromptTemplate(
       input_variables=["chunks", "message"],
       template=(
           "Answer the user query by using only the provided context.\n"
           "Context:\n{chunks}\n\nUser: {message}"
       ),
   )

VECTORSTORE = ensure_vectorstore(MENU_PDF, INDEX_DIR)
RETRIEVER = VECTORSTORE.as_retriever(search_kwargs={"k": 4})    #F
LLM = ChatOpenAI(model="gpt-4o-mini", temperature=0.1)    #G
PROMPT = build_prompt()

def answer_query(question: str) - > str:    #H
   """Retrieve Chroma chunks then ground the final answer in that context."""

   docs = RETRIEVER.invoke(question)
   context = "\n\n".join(doc.page_content for doc in docs)
   final_prompt = PROMPT.format(chunks=context, message=question)
   response = LLM.invoke(final_prompt)
   return response.content

def chat_loop() - > None:
   """Terminal REPL so you can interrogate the menu like the Langflow chat."""

   try:
       while True:
           user_question = input("Your PizzaMate question: ")
           answer = answer_query(user_question)
           print("\nAI:", answer, "\n")
   except KeyboardInterrupt:
           print("\nEnjoy your slice!")

if __name__ == "__main__":
   chat_loop()

The Python listing makes the workflow concrete by mapping document loading, recursive text splitting, OpenAI embeddings, local Chroma storage, retrieval, and guarded prompting to reusable functions. section 4.4

How Grokking AI Applications covers it

How deep it goes
Configures collections, disk persistence, ingestion, and top-match retrieval, without descending into vector-database internals.
Examples
Uses a pizzeria menu PDF, overlapping text chunks, a menu collection, and a menu persistence directory.
What you can do after
Build it from scratch as a local Chroma-backed RAG ingestion and retrieve-and-generate pipeline.
How it connects
Connects document loaders, text splitters, embeddings, RAG, retrievers, prompt templates, and language models.

Also explained in

Compare how 7 books explain Chroma DB →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Grokking AI Applications. The section links point to the parts of the book it draws on.