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






