Vector Stores
Comparing a question with every chunk one by one (Lab 08) is fine for 5 FAQs, not for 5 million chunks. A vector store is a database built for this: it keeps the vector, the text and the metadata together and finds the nearest chunks in milliseconds. In this lab you use three of them: in-memory, FAISS (a file on disk) and Chroma (a small local database).
In this session
- What a vector store keeps: vector + text + metadata
- InMemoryVectorStore for learning
- FAISS: fast, save and load from disk
- Chroma: persistent, metadata filters, delete
- Score direction: similarity vs distance
- MMR: relevant and diverse
01The big idea: a library index for meanings
Think of a library catalogue. Instead of reading every book, you look up the catalogue and go straight to the right shelf. A vector store is a catalogue sorted by meaning: you give it the question’s vector and it returns the nearest chunks, with their labels (metadata) so you can filter, for example only the “UPI” shelf.
| Store | Type | Good for |
|---|---|---|
InMemoryVectorStore | RAM | learning, small demos |
FAISS | local file | fast, offline, save/load |
Chroma | local DB | persistent, metadata filters, delete by id |
| Pinecone, Qdrant, Weaviate, pgvector, Azure AI Search | cloud | production, millions of chunks, many users |
02Search, scores, filters and MMR
| Operation | Code |
|---|---|
| search top-k | store.similarity_search("lost card", k=2) |
| with scores | store.similarity_search_with_score(q, k=3) |
| filter by metadata | store.similarity_search("limit", k=2, filter={"topic": "upi"}) |
| add later | store.add_documents([doc], ids=["offer-1"]) |
| delete | chroma_store.delete(ids=["offer-1"]) |
| save / load FAISS | save_local("idx") / FAISS.load_local("idx", emb, allow_dangerous_deserialization=True) |
| diverse results | max_marginal_relevance_search(q, k=2, fetch_k=6) |
allow_dangerous_deserialization=True is needed because FAISS indexes are saved with pickle. Only load index files that you created; a pickle from a stranger can run code.03Hands-on: run it here
The notebook’s six NovaBank documents in InMemory and FAISS: scores, save and reload from disk, add a new FD document, filter by topic and MMR.
import warnings; warnings.filterwarnings("ignore")
from standins import KeywordEmbeddings
from langchain_core.documents import Document
from langchain_core.vectorstores import InMemoryVectorStore
from langchain_community.vectorstores import FAISS
embeddings = KeywordEmbeddings() # Colab: HuggingFaceEmbeddings("sentence-transformers/all-MiniLM-L6-v2")
docs = [Document("Report a lost card within 3 days for zero liability.", metadata={"topic": "cards", "id": 1}),
Document("Card-not-present payments above Rs 5,000 need OTP.", metadata={"topic": "cards", "id": 2}),
Document("UPI limit for a new payee is Rs 25,000 in the first 24 hours.", metadata={"topic": "upi", "id": 3}),
Document("Never share your UPI PIN with anyone.", metadata={"topic": "upi", "id": 4}),
Document("Video KYC is available from 9 AM to 9 PM.", metadata={"topic": "kyc", "id": 5}),
Document("Home loan interest starts at 8.5% per year.", metadata={"topic": "loans", "id": 6})]
store = InMemoryVectorStore.from_documents(docs, embeddings)
print("InMemory, cosine (higher = closer):")
for d, s in store.similarity_search_with_score("I lost my card, what should I do?", k=2): print(f" {s:.3f} {d.page_content}")
faiss_store = FAISS.from_documents(docs, embeddings)
print("FAISS, L2 distance (LOWER = closer):")
for d, s in faiss_store.similarity_search_with_score("loan interest rate", k=2): print(f" {s:.3f} {d.page_content}")
faiss_store.save_local("faiss_bank_index")
loaded = FAISS.load_local("faiss_bank_index", embeddings, allow_dangerous_deserialization=True)
print("reloaded from disk:", loaded.similarity_search("video KYC timing", k=1)[0].page_content)
faiss_store.add_documents([Document("Fixed deposit rate is 7.1% for 1 year.", metadata={"topic": "deposits", "id": 7})])
print("after add:", faiss_store.similarity_search("FD deposit rate", k=1)[0].page_content)
print("filter topic=upi:", [d.page_content for d in faiss_store.similarity_search("limit", k=2, filter={"topic": "upi"})])
print("MMR (diverse):", [d.metadata["id"] for d in faiss_store.max_marginal_relevance_search("card rules", k=2, fetch_k=6)])KeywordEmbeddings in standins.py) stands in for MiniLM, so every output below is real, but the scores are smaller than MiniLM’s. In Colab use HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2").04Hands-on: Ajeetkumar’s Colab notebook
groq_key with your free key from console.groq.com, switch on Notebook access, then run the cells from the top.Outputs labelled stand-in embeddings, including all the Chroma cells, are from re-running the notebook here with the keyword stand-in.
05Practice tasks
- Load a PDF, split it, store it in FAISS, save and reload it.
- Store 20 product descriptions in Chroma with
categorymetadata and filter by category. - Compare FAISS vs InMemory scores for the same question.
Try these in the same Colab notebook after you finish the lab. Change one thing at a time and look at the output again.
06Summary
- A vector store keeps vector + text + metadata and finds nearest chunks fast.
- InMemory for learning, FAISS for local files, Chroma for a persistent local DB, cloud stores for production.
- Check the score: similarity (higher better) or distance (lower better).
- Metadata filters search inside one topic, user or date range.
- MMR returns relevant and diverse chunks.
07Quick quiz
1. FAISS similarity_search_with_score returns 0.3 and 1.2. Which is closer?
2. Search only UPI documents?
3. Which store survives a restart with no extra code?
4. What does MMR add?
5. Why is allow_dangerous_deserialization needed for FAISS?