Giving Models Memory: Embeddings & Similarity
Business Scenario
Welcome!
Previously, you installed Ollama, ran an open-weight model locally, integrated it through LangChain and compared cloud and local latency. You estimated cloud token costs, examined shopper data privacy, and made SmartCart AI v2 backend-swappable using get_llm(), testing both backends on the same conversation.
Today, your manager has assigned you a task to build a standalone semantic search demo for SmartCart AI. You will use embeddings to compare the meaning of a shopper's query with product names and descriptions, then rank products by how closely they match the query. This will help SmartCart find relevant products even when shoppers use different words and lay the foundation for connecting catalogue search to Kart.
Git Pull
git pull origin branchNamePre-Lab Preparation
Dataset :
Topic : Giving Models Memory Embedding & Similarity
1) Text Embeddings
2) Embedding Models
3) Cosine Similarity
Task 1: Load an Embedding Model
!pip install -q langchain-huggingface sentence-transformers
!echo "langchain-huggingface" >> requirements.txt
!echo "sentence-transformers" >> requirements.txt
import numpy as np
import pandas as pd
from langchain_huggingface import HuggingFaceEmbeddings
embedder = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
print("Embedding model ready")Task 2 : What am Embedding looks like
vector = embedder.embed_query("wireless earbuds for the gym")
print("Type :", type(vector).__name__)
print("Length :", len(vector))
print("First 8 :", np.round(vector[:8], 3))Output
Task 3: Cosine Similarity from Scratch
def cosine_similarity(a, b):
"""1 = same direction, 0 = unrelated, -1 = opposite."""
a, b = np.array(a), np.array(b)
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
print(round(cosine_similarity([1, 2], [2, 4]), 2)) # same direction
print(round(cosine_similarity([1, 2], [2, -1]), 2)) # right angle
print(round(cosine_similarity([1, 2], [-1, -2]), 2)) # oppositeWrite the function and test it on tiny two-number vectors.
1
Compare all real shopping phrases
2
pairs = [
("wireless earbuds", "bluetooth headphones"),
("wireless earbuds", "earbuds wireless"),
("wireless earbuds", "basmati rice 5 kg"),
("formal shirt for work", "office ke liye formal shirt"),]
for a, b in pairs:
score = cosine_similarity(embedder.embed_query(a), embedder.embed_query(b))
print(f"{score:.2f} '{a}' vs '{b}'")Output
Output
Task 4 : Embeddings vs TF-IDF
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity as sklearn_cosine
a, b = "wireless earbuds", "bluetooth headphones"
tfidf = TfidfVectorizer().fit_transform([a, b])
print("TF-IDF similarity :", round(sklearn_cosine(tfidf[0], tfidf[1])[0][0], 2))
print("Embedding similarity :", round(cosine_similarity(embedder.embed_query(a),
embedder.embed_query(b)), 2))Output
Task 5 : Ranking products by Meaning
Embed the Catalogue
1
products = pd.read_csv("smartcart_products.csv")
product_texts = (products["name"] + ". " + products["description"]).tolist()
product_vectors = embedder.embed_documents(product_texts)
print(len(product_vectors), "products embedded,", len(product_vectors[0]), "numbers each")
print(products[["product_id", "name", "category",
"price_rs"]].head(3).to_string(index=False))Output
def search_products(query, top_k=3):
"""Return the top_k products closest in meaning to the query."""
query_vector = embedder.embed_query(query)
scores = [cosine_similarity(query_vector, v) for v in product_vectors]
ranked = products.assign(score=np.round(scores, 2))
return ranked.sort_values("score", ascending=False).head(top_k)
for query in ["something to listen to music while running",
"healthy breakfast",
"clothes for a wedding"]:
print("Query:", query)
print(search_products(query)[["name", "category", "price_rs",
"score"]].to_string(index=False), "\n")Search the catalogue with phrases a keyword search would miss
2
Output
Task 6 : Find Similar Products
def similar_products(product_id, top_k=3):
"""Return the top_k products most similar to the given product."""
row = products.index[products["product_id"] == product_id][0]
scores = [cosine_similarity(product_vectors[row], v) for v in product_vectors]
ranked = products.assign(score=np.round(scores, 2))
ranked = ranked[ranked["product_id"] != product_id] # skip the product itself
return ranked.sort_values("score", ascending=False).head(top_k)
print("Customers who viewed boAt Airdopes 141 also viewed:")
print(similar_products("P01")[["name", "price_rs", "score"]].to_string(index=False))Save the script
1
%%writefile smartcart_similarity.py
import numpy as np
import pandas as pd
from langchain_huggingface import HuggingFaceEmbeddings
embedder = HuggingFaceEmbeddings(
model_name="sentence-transformers/all-MiniLM-L6-v2")
products = pd.read_csv("smartcart_products.csv")
product_vectors = embedder.embed_documents(
(products["name"] + ". " + products["description"]).tolist())
def cosine_similarity(a, b):
"""1 = same direction, 0 = unrelated, -1 = opposite."""
a, b = np.array(a), np.array(b)
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
Output
Task 7 : Build the Standalone Similarity Demo
%%writefile smartcart_similarity.py
import numpy as np
import pandas as pd
from langchain_huggingface import HuggingFaceEmbeddings
embedder = HuggingFaceEmbeddings(
model_name="sentence-transformers/all-MiniLM-L6-v2")
products = pd.read_csv("smartcart_products.csv")
product_vectors = embedder.embed_documents(
(products["name"] + ". " + products["description"]).tolist())
def cosine_similarity(a, b):
"""1 = same direction, 0 = unrelated, -1 = opposite."""
a, b = np.array(a), np.array(b)
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
def rank_products(query, top_k=3):
"""Return the top_k products closest in meaning to the query."""
query_vector = embedder.embed_query(query)
scores = [
cosine_similarity(query_vector, v)
for v in product_vectors]
ranked = products.assign(score=np.round(scores, 2))
return ranked.sort_values("score", ascending=False).head(top_k)
if __name__ == "__main__":
print(
f"SmartCart similarity demo -- {len(products)} products. "
"Type 'quit' to exit.")
while True:
query = input("\nSearch: ").strip()
if query.lower() in ["quit", "exit", "bye"]:
break
if query == "":
continue
for _, p in rank_products(query).iterrows():
bar = "#" * int(max(0, p["score"]) * 20)
print(
f" {p['score']:.2f} {bar:<20} "
f"{p['name']} (Rs. {p['price_rs']:,})")Run it
2
%run smartcart_similarity.pyOutput
Test where the meaning based search falls short
3
from smartcart_similarity import rank_products
for query in ["earbuds under 1000 rupees", "earbuds that are not boAt", "M185"]:
top = rank_products(query, top_k=1).iloc[0]
print(f"{query:<28} -> {top['name']} (Rs. {top['price_rs']:,}, score {top['score']})")Output
Great job!
You have successfully explored dimensional text embeddings, implemented cosine similarity from scratch, compared semantic matching with TF-IDF. You ranked the catalogue by meaning, built a “Customers Also Viewed” list, created smartcart_similarity.py, identifying its limitations with prices & exact product codes.
Checkpoint
Git Push
git push origin branchNameNext-Lab Preparation
Topic : Vector Databases, Semantic Search & RAG Data Layer
1) Vector Databases (Chroma & FAISS)
2) Document Loading & Chunking
3) RAG Architecture