LangChain Hands-on · Module 2 · Lab 08

Embeddings

⏱ 20 min + hands-on🎯 Beginner🖼 1 diagram🧪 2 live demos🐍 Python code

Computers cannot compare meanings, but they are very good at comparing numbers. An embedding turns text into a list of numbers (a vector) so that similar meanings get similar numbers: “lost credit card” lands next to “stolen debit card”, far away from “biryani recipe”. That one idea powers semantic search, RAG and recommendations.

In this session

  • Text → vector that captures meaning
  • Free MiniLM embeddings on Colab
  • embed_query vs embed_documents
  • Cosine similarity by hand
  • Mini semantic search without a database
  • Other providers and CacheBackedEmbeddings

01The big idea: GPS coordinates for meaning

📍

Think of GPS coordinates. Pune and Mumbai have close latitude and longitude; Pune and London are far apart. An embedding gives every sentence “coordinates” in a space with hundreds of directions. Sentences about cards sit in one neighbourhood, food in another. Search becomes “find the nearest neighbours”.

2-D picture of embedding space (real vectors have 384+ numbers)lost credit cardstolen debit cardblock my cardUPI payment failedmoney not receivedbest biryani in Hyderabadmasala dosa recipeclose = similarfar apart = unrelated
Similar meanings sit close together, even with different words (“lost” and “stolen”). Search = find the nearest points to the question.

Cosine similarity measures how much two vectors point the same way: 1 = same meaning, 0 = unrelated. It is one line of NumPy:

cosine.py
def cosine(a, b):
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

02embed_query, embed_documents and providers

MethodInputOutputUse for
embed_query(text)one stringone vector (384 numbers for MiniLM)the user’s question
embed_documents(list)many stringslist of vectorsyour chunks, once, at indexing time
ModelCostDimsNote
all-MiniLM-L6-v2 (HuggingFace)free384fast, good for learning, runs on Colab CPU
bge / e5 (HuggingFace)free768–1024better quality
OpenAI text-embedding-3-smallpaid, cheap1536strong, popular
Gemini embeddingpaid / free tier3072multilingual
Golden rule: use the same embedding model for documents and questions. Vectors from different models live in different “maps”, so comparing them is meaningless.
Demo · Mini semantic search: which FAQ wins?

03Hands-on: run it here

The notebook’s similarity table and FAQ search, with a no-download stand-in embedding. With MiniLM in Colab the numbers are different (and unrelated pairs are not exactly 0), but the ranking idea is the same.

lab08_embeddings.py
import numpy as np
from standins import KeywordEmbeddings
# In Colab: embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
embeddings = KeywordEmbeddings(dim=384)

vector = embeddings.embed_query("How do I block my lost card?")
print("dims:", len(vector), "| non-zero values:", {i: v for i, v in enumerate(vector) if v})

def cosine(a, b): return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))
sentences = ["lost credit card", "stolen debit card", "best biryani in Hyderabad", "UPI payment failed"]
vectors = embeddings.embed_documents(sentences)
for i in range(len(sentences)):
    for j in range(i + 1, len(sentences)):
        print(f"  {sentences[i]:<26} vs {sentences[j]:<26} -> {cosine(vectors[i], vectors[j]):.3f}")

faq = ["How to reset my net banking password?", "What is the daily UPI limit?", "How to block a stolen card?",
       "How to update my mobile number?", "What are the home loan interest rates?"]
faq_vectors = embeddings.embed_documents(faq)
def search(question):
    q = embeddings.embed_query(question)
    scores = [cosine(q, v) for v in faq_vectors]
    best = int(np.argmax(scores))
    return faq[best], round(scores[best], 3)
for q in ["someone took my debit card", "forgot my login password", "loan rate for a house"]:
    print("search:", q, "->", search(q))
dims: 384 | non-zero values: {42: 0.378, 105: 0.378, 267: 0.378, 299: 0.378, 322: 0.378, 351: 0.378, 371: 0.378} lost credit card vs stolen debit card -> 0.772 lost credit card vs best biryani in Hyderabad -> 0.000 lost credit card vs UPI payment failed -> 0.000 stolen debit card vs best biryani in Hyderabad -> 0.000 stolen debit card vs UPI payment failed -> 0.000 best biryani in Hyderabad vs UPI payment failed -> 0.000 search: someone took my debit card -> ('How to block a stolen card?', 0.478) search: forgot my login password -> ('How to reset my net banking password?', 0.535) search: loan rate for a house -> ('What are the home loan interest rates?', 0.309)
Runs here without downloads. A tiny keyword embedding (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

Colab setup (same in every notebook): click 🔑 Secrets in the Colab sidebar, add groq_key with your free key from console.groq.com, switch on Notebook access, then run the cells from the top.
Demo · Notebook player · Lab 08

Outputs labelled stand-in embeddings came from re-running the notebook with the keyword stand-in (no 90 MB download): same cells and data, different numbers from MiniLM.

05Practice tasks

  1. Embed 10 movie plots and find the closest one to “a robot falls in love”.
  2. Compare the similarity of the Hindi and English versions of the same sentence.
  3. Try BAAI/bge-small-en-v1.5 and compare scores with MiniLM.

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

07Quick quiz

1. What does an embedding capture?

2. Which method for the user’s question?

3. Cosine similarity of 0.95 means…

4. Docs embedded with MiniLM, questions with OpenAI. Problem?

5. How many numbers in an all-MiniLM-L6-v2 vector?

08References

Created by Ajeetkumar