This episode covers integrating ChromaDB with LLM frameworks: making it a VectorStore and retriever in LangChain, LlamaIndex and other framework adapters, and a complete production RAG pattern from chunking, embedding, and storage to querying.

All the ChromaDB capabilities you have built since episode 0 now come together. Episode 18 covers integration with LLM frameworks — the part that turns ChromaDB from a database into a retrieval engine ready for RAG pipelines.
We will cover LangChain integration as a VectorStore and retriever, LlamaIndex and other framework adapters, then assemble them into a complete production RAG pattern: chunking, embedding, storage, and querying in one flow. This is the episode that answers "so, how do I actually use it?".
The official LangChain integration lives in the langchain-chroma package. Install and connect:
pip install langchain langchain-chromafrom langchain_chroma import Chroma
vectorstore = Chroma(
collection_name="dokumen",
persist_directory="./chroma-data",
embedding_function=embedding_model,
)Chroma(collection_name="dokumen", persist_directory="./chroma-data", embedding_function=embedding_model) creates a VectorStore wrapped around ChromaDB. All the complexity from episodes 3-10 is hidden — LangChain manages the collection and embedding function for you.
With a VectorStore, storing documents becomes a single call:
from langchain_text_splitters import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_text(dokumen_panjang)
vectorstore.add_texts(
texts=chunks,
metadatas=[{"source": "manual"} for _ in chunks],
)splitter.split_text(dokumen_panjang) splits the document using the chunking from episode 10, then vectorstore.add_texts(...) stores it. Note that chunk_size and chunk_overlap here are the direct realization of episode 10's strategy.
Info
LangChain and ChromaDB embedding functions can be used together — langchain_chroma accepts embeddings from both worlds. Make sure the model stays consistent, as emphasized in episode 6.
Turning the VectorStore into a retriever is as easy as calling .as_retriever():
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 4},
)vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 4}) produces a retriever that returns the top 4 documents for every question. The k parameter is equivalent to n_results from episode 5.
Now assemble everything into an answering pipeline:
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
llm = ChatOpenAI(model="gpt-4o-mini")
prompt = ChatPromptTemplate.from_template(
"Jawab berdasarkan konteks ini:\n{context}\n\nPertanyaan: {question}"
)
def jawab(pertanyaan):
dokumen = retriever.invoke(pertanyaan)
konteks = "\n\n".join(d.text for d in dokumen)
pesan = prompt.format_messages(context=konteks, question=pertanyaan)
return llm.invoke(pesan).contentThe jawab(pertanyaan) function runs the most core RAG pattern: retrieve context from ChromaDB, attach it to the prompt, then generate an answer with the LLM. This is the embed → store → retrieve → generate flow from episode 0 in concrete form.
LlamaIndex also has an official adapter. The flow: create a storage context, then use VectorStoreIndex:
import chromadb
from llama_index.core import VectorStoreIndex, StorageContext
from llama_index.vector_stores.chroma import ChromaVectorStore
chroma_client = chromadb.PersistentClient(path="./chroma-data")
collection = chroma_client.get_collection("dokumen")
vector_store = ChromaVectorStore(chroma_collection=collection)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)ChromaVectorStore(chroma_collection=collection) wraps a ChromaDB collection into a LlamaIndex vector store. From here, index.as_query_engine() can be used directly for asking questions.
ChromaDB also integrates with other frameworks such as Haystack and LlamaStack. The pattern is consistent everywhere: the framework provides the adapter, ChromaDB provides storage and retrieval, and the embedding function stays from episode 6. The key is not memorizing each framework's API, but understanding the VectorStore concept — once you get it, all adapters feel familiar.
Summarizing episodes 0-18 into a production-ready RAG architecture:
dokumen ──chunk──> embedding ──store──> ChromaDB
│
pertanyaan ──embed──> query ──filter+rerank──> konteks
│
konteks + pertanyaan ──prompt──> LLM ──> jawabanThe pipeline above combines: chunking (episode 10), embedding (episode 6), metadata filtering (episode 7), hybrid and rerank (episode 8), and the LLM as generator. You have mastered every stage in its own episode.
Before landing in production, make sure:
retriever = vectorstore.as_retriever(
search_kwargs={
"k": 6,
"filter": {"status": "published"},
}
)retriever.as_retriever(search_kwargs={"k": 6, "filter": {"status": "published"}}) injects a metadata filter directly into retrieval — the realization of episode 17's pre-filtering at the framework level.
Episode 18 unified the entire series into one goal: a working RAG. You can now make ChromaDB a VectorStore and retriever in LangChain, use the LlamaIndex adapter, and assemble a production RAG pipeline from chunking to answers. ChromaDB is no longer just a database — it is the retrieval engine of your AI application.
Key takeaways:
langchain_chroma wraps ChromaDB as a VectorStore and retriever.as_retriever() turns a VectorStore into a RAG component.ChromaVectorStore as its adapter.In the next episode, episode 19, we will discuss advanced query patterns — multi-vector and multimodal with multiple embeddings per document, image and text embeddings, and feedback loops with relevance scoring and human feedback for continuous retrieval tuning. Your retrieval is smart; now it is time to make it smarter.