Module 1: What Are Embeddings?
Real-World Use Cases of Embeddings
Capsule overview
Embeddings are not just an abstract mathematical concept—they are the underlying technology of the most widely used AI applications in production today.
In this capsule you'll learn the 5 main use cases of embeddings in real systems: semantic search, RAG (Retrieval-Augmented Generation), recommendation systems, document classification, and clustering. You'll see concrete examples of companies that use embeddings in production and understand why they are critical for AI Engineering.
You'll also learn to identify when to use embeddings vs other techniques (keyword search, rules, etc.).
Use Case #1: Semantic Search
What it is:
Search by meaning, not by exact keywords.
Traditional example (keyword search):
User searches: "how to reset my laptop"
Keyword system (BM25):
✅ Finds: "reset laptop", "laptop reset"
❌ Does NOT find: "restart computer", "reboot PC", "restore notebook"
With embeddings (semantic search):
User searches: "how to reset my laptop"
Semantic system:
✅ Finds: "reset laptop"
✅ Finds: "restart computer" (synonym)
✅ Finds: "reboot PC" (conceptual match)
✅ Finds: "restore notebook" (paraphrase)
Why it works: Embeddings capture that "reset", "restart", "reboot", "restore" are conceptually similar.
Typical architecture:
1. Indexing (offline phase):
Documents → Embed each doc → Store in vector DB
2. Query (online phase):
User query → Embed query → Find top-K similar → Return docs
Conceptual code:
from openai import OpenAI
import numpy as np
client = OpenAI()
# Step 1: Indexing (once)
documents = [
"How to reset your Windows laptop",
"Restart Mac computer",
"Reboot PC after an update",
"Restore notebook to factory settings"
]
# Generate embeddings for the documents
doc_embeddings = []
for doc in documents:
response = client.embeddings.create(
model="text-embedding-3-small",
input=doc
)
doc_embeddings.append(response.data[0].embedding)
# Step 2: Query (each time the user searches)
query = "how to reset my laptop"
query_response = client.embeddings.create(
model="text-embedding-3-small",
input=query
)
query_embedding = query_response.data[0].embedding
# Step 3: Calculate similarities
def cosine_similarity(vec_a, vec_b):
return np.dot(vec_a, vec_b) / (
np.linalg.norm(vec_a) * np.linalg.norm(vec_b)
)
similarities = []
for i, doc_emb in enumerate(doc_embeddings):
sim = cosine_similarity(query_embedding, doc_emb)
similarities.append((i, sim))
# Sort by similarity
similarities.sort(key=lambda x: x[1], reverse=True)
# Return top-3
print("Most relevant results:")
for rank, (doc_id, sim) in enumerate(similarities[:3], 1):
print(f"{rank}. {documents[doc_id]} (score: {sim:.4f})")
Expected output:
Most relevant results:
1. How to reset your Windows laptop (score: 0.92)
2. Restore notebook to factory settings (score: 0.88)
3. Restart Mac computer (score: 0.85)
Companies using semantic search:
| Company | Application | Scale |
|---|---|---|
| Notion | Search in workspace (docs, notes) | Millions of users |
| Slack | Search messages/files | Millions of messages/day |
| GitHub | Code search (find code by function) | Millions of repos |
| Shopify | Product search (find products by description) | Millions of products |
| Intercom | Help center search | Hundreds of thousands of articles |
Competitive advantage: Users find what they're looking for even with imprecise queries.
Use Case #2: RAG (Retrieval-Augmented Generation)
What it is:
Giving an LLM access to external knowledge via semantic search.
Problem without RAG:
User: "What is my company's vacation policy?"
LLM without RAG:
"I don't have information about your company's specific policies.
Generally, companies offer 15-20 days..." ❌ Generic
Solution with RAG:
User: "What is my company's vacation policy?"
RAG system:
1. Searches internal docs with embeddings
2. Finds: "Vacation policy 2026: 25 business days..."
3. LLM responds with that context:
"According to your company's policy (2026), you have 25 business days..." ✅ Specific
Full RAG flow:
1. INDEXING (offline):
Company documents → Chunking → Embed chunks → Vector DB
2. RETRIEVAL (online):
User query → Embed query → Top-K similar chunks
3. AUGMENTATION (online):
Build prompt: "Context: [chunks]\n\nQuestion: [query]"
4. GENERATION (online):
LLM generates an answer using the context
Conceptual code:
from openai import OpenAI
import numpy as np
client = OpenAI()
# Step 1: Index documents (internal company)
knowledge_base = [
"Vacation policy 2026: Employees are entitled to 25 business days of vacation per year.",
"Work schedule: Monday to Friday 9am-6pm. Flexible Fridays (home office).",
"Medical benefits: Health insurance covered 100% for the employee and 50% for family."
]
kb_embeddings = []
for doc in knowledge_base:
response = client.embeddings.create(
model="text-embedding-3-small",
input=doc
)
kb_embeddings.append(response.data[0].embedding)
# Step 2: User asks a question
user_question = "How many vacation days do I have?"
# Step 3: Retrieval (find relevant context)
query_response = client.embeddings.create(
model="text-embedding-3-small",
input=user_question
)
query_embedding = query_response.data[0].embedding
# Find the top-1 most relevant
similarities = [
(i, cosine_similarity(query_embedding, kb_emb))
for i, kb_emb in enumerate(kb_embeddings)
]
similarities.sort(key=lambda x: x[1], reverse=True)
most_relevant_idx = similarities[0][0]
context = knowledge_base[most_relevant_idx]
print(f"Retrieved context: {context}\n")
# Step 4: Augmented prompt
augmented_prompt = f"""Context: {context}
Question: {user_question}
Answer using ONLY the information from the provided context."""
# Step 5: Generation
chat_response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": augmented_prompt}]
)
answer = chat_response.choices[0].message.content
print(f"RAG answer: {answer}")
Output:
Retrieved context: Vacation policy 2026: Employees are entitled to 25 business days of vacation per year.
RAG answer: According to the 2026 vacation policy, you are entitled to 25 business days of vacation per year.
Companies using RAG:
| Company | Application | Data |
|---|---|---|
| Notion AI | Q&A about the user's workspace | Private docs |
| ChatGPT (GPTs) | Custom GPTs with specific knowledge | PDFs, websites |
| Perplexity | Search with citations | Web crawl |
| Intercom Fin | Customer support automation | Help center |
| Glean | Enterprise search with AI | Confluence, Google Drive, Slack |
Value: LLMs respond with up-to-date, context-specific information.
Use Case #3: Recommendation Systems
What it is:
Suggest similar content based on item embeddings.
Example: Netflix
User is watching: "Stranger Things"
System:
1. Embed the description of "Stranger Things"
2. Search for shows with similar embeddings
3. Recommend: "Dark", "The Umbrella Academy", "Black Mirror"
Why it works: Embeddings capture themes (sci-fi, supernatural, drama).
Typical architecture:
1. Embed all items (movies, products, articles)
2. User consumes item X
3. Search for items with embeddings similar to X
4. Recommend the top-K most similar
Conceptual code:
# Step 1: Index products (e-commerce)
products = [
{"id": 1, "name": "Laptop Dell XPS 13", "desc": "Compact ultrabook laptop for development"},
{"id": 2, "name": "Laptop MacBook Pro", "desc": "Premium laptop for creatives and developers"},
{"id": 3, "name": "Mouse Logitech MX Master", "desc": "Ergonomic mouse for productivity"},
{"id": 4, "name": "Mechanical keyboard", "desc": "Mechanical keyboard for gaming and programming"},
{"id": 5, "name": "4K monitor", "desc": "Ultra HD monitor for design and editing"}
]
# Embed products
product_embeddings = {}
for product in products:
response = client.embeddings.create(
model="text-embedding-3-small",
input=product["desc"]
)
product_embeddings[product["id"]] = response.data[0].embedding
# Step 2: User viewed product X
user_viewed_product_id = 1 # Laptop Dell XPS 13
user_viewed_embedding = product_embeddings[user_viewed_product_id]
# Step 3: Find similar products
similarities = []
for prod_id, prod_emb in product_embeddings.items():
if prod_id == user_viewed_product_id:
continue # Don't recommend the same one
sim = cosine_similarity(user_viewed_embedding, prod_emb)
similarities.append((prod_id, sim))
similarities.sort(key=lambda x: x[1], reverse=True)
# Step 4: Recommend top-3
print("Recommended products:")
for rank, (prod_id, sim) in enumerate(similarities[:3], 1):
product = next(p for p in products if p["id"] == prod_id)
print(f"{rank}. {product['name']} (score: {sim:.4f})")
Output:
Recommended products:
1. Laptop MacBook Pro (score: 0.88)
2. Mechanical keyboard (score: 0.72)
3. 4K monitor (score: 0.68)
Companies using recommendations with embeddings:
| Company | Application | Method |
|---|---|---|
| Netflix | Movie/show recommendations | Description embeddings + user behavior |
| Spotify | Song/playlist recommendations | Audio embeddings + metadata |
| Amazon | Product recommendations | Product description embeddings |
| Medium | Article recommendations | Article content embeddings |
| YouTube | Video recommendations | Video title/description embeddings |
Use Case #4: Document Classification
What it is:
Classify documents into categories using embeddings + a simple classifier.
Example: Email routing
Email: "My invoice has an error in the amount..."
System:
1. Embed the email
2. Compare with category embeddings:
- Billing
- Technical Support
- Sales
3. Classify as "Billing"
4. Route to the correct team
Typical architecture:
1. Train (create category embeddings):
- Embed examples of each category
- Calculate an "average embedding" per category
2. Classify (runtime):
- Embed a new document
- Calculate similarity to each category
- Assign to the most similar category
Conceptual code:
# Step 1: Define categories with examples
categories = {
"Billing": [
"My invoice has an error",
"I want to cancel my subscription",
"I don't recognize this charge"
],
"Technical Support": [
"The app won't load",
"Error when logging in",
"I can't access my account"
],
"Sales": [
"I want information about the enterprise plan",
"What is the price of the Pro plan?",
"I need a demo of the product"
]
}
# Step 2: Create an average embedding per category
category_embeddings = {}
for category, examples in categories.items():
# Embed each example
embeddings = []
for example in examples:
response = client.embeddings.create(
model="text-embedding-3-small",
input=example
)
embeddings.append(response.data[0].embedding)
# Average
category_embeddings[category] = np.mean(embeddings, axis=0)
# Step 3: Classify a new document
new_email = "I can't pay my invoice from last month"
email_response = client.embeddings.create(
model="text-embedding-3-small",
input=new_email
)
email_embedding = email_response.data[0].embedding
# Step 4: Find the most similar category
similarities = []
for category, cat_emb in category_embeddings.items():
sim = cosine_similarity(email_embedding, cat_emb)
similarities.append((category, sim))
similarities.sort(key=lambda x: x[1], reverse=True)
print(f"Email: '{new_email}'")
print(f"\nClassified as: {similarities[0][0]} (score: {similarities[0][1]:.4f})")
Output:
Email: 'I can't pay my invoice from last month'
Classified as: Billing (score: 0.89)
Companies using classification:
| Company | Application | Categories |
|---|---|---|
| Zendesk | Ticket routing | 10-50 categories (billing, tech, sales...) |
| Gmail | Smart categorization | Primary, Social, Promotions, Updates |
| Superhuman | Email triage | Important, Later, Archive |
| Content moderation | Spam, Hate speech, Safe |
Use Case #5: Document Clustering
What it is:
Automatically group similar documents without predefined categories.
Example: Organizing support tickets
1000 unlabeled tickets
Clustering system:
1. Embed all tickets
2. Apply clustering (K-Means)
3. Automatic result:
- Cluster 1: Login problems (~250 tickets)
- Cluster 2: Billing errors (~180 tickets)
- Cluster 3: App bugs (~320 tickets)
- Cluster 4: Questions about features (~200 tickets)
- Cluster 5: Other (~50 tickets)
Typical architecture:
1. Embed all documents
2. Apply a clustering algorithm:
- K-Means (if you know the # of clusters)
- DBSCAN (if you do NOT know the # of clusters)
3. Analyze the resulting clusters
4. Label clusters manually (optional)
Conceptual code:
from sklearn.cluster import KMeans
import numpy as np
# Step 1: Documents to cluster
documents = [
"I can't log in to my account",
"Error when signing in",
"My invoice has an incorrect amount",
"Duplicate charge on my card",
"The app closes unexpectedly",
"Crash when opening the app",
"How does feature X work?",
"Documentation about feature Y"
]
# Step 2: Generate embeddings
doc_embeddings = []
for doc in documents:
response = client.embeddings.create(
model="text-embedding-3-small",
input=doc
)
doc_embeddings.append(response.data[0].embedding)
doc_embeddings_array = np.array(doc_embeddings)
# Step 3: Clustering with K-Means (4 clusters)
kmeans = KMeans(n_clusters=4, random_state=42)
clusters = kmeans.fit_predict(doc_embeddings_array)
# Step 4: Show results
from collections import defaultdict
clustered_docs = defaultdict(list)
for doc, cluster_id in zip(documents, clusters):
clustered_docs[cluster_id].append(doc)
print("Automatic clustering:")
for cluster_id, docs in clustered_docs.items():
print(f"\nCluster {cluster_id}:")
for doc in docs:
print(f" - {doc}")
Expected output:
Automatic clustering:
Cluster 0:
- I can't log in to my account
- Error when signing in
Cluster 1:
- My invoice has an incorrect amount
- Duplicate charge on my card
Cluster 2:
- The app closes unexpectedly
- Crash when opening the app
Cluster 3:
- How does feature X work?
- Documentation about feature Y
Companies using clustering:
| Company | Application | Scale |
|---|---|---|
| Zendesk | Identify common topics in tickets | Millions of tickets |
| Group trending tweets | Thousands of tweets/second | |
| Google News | Group news about the same event | Thousands of articles/day |
| Group similar posts | Millions of posts |
Comparison: When to use embeddings
Embeddings vs Keyword Search:
| Aspect | Keyword Search (BM25) | Embeddings (Semantic) |
|---|---|---|
| Exact search | ✅ Excellent | ⚠️ May over-generalize |
| Synonyms | ❌ Doesn't find | ✅ Finds |
| Paraphrases | ❌ Doesn't find | ✅ Finds |
| IDs, codes | ✅ Perfect | ❌ May confuse |
| Multilingual search | ❌ Difficult | ✅ Works (if multilingual model) |
| Speed | ✅ Very fast | ⚠️ Slower (requires a special index) |
| Cost | ✅ Free (Elasticsearch) | ⚠️ API calls (or local GPU) |
Best approach: Hybrid (keyword + semantic).
Embeddings vs Rules:
| Use Case | Rules | Embeddings |
|---|---|---|
| Email routing | Rules: if "invoice" → Billing | ✅ Better: Captures variations |
| Spam detection | Rules: Keyword blacklist | ✅ Better: Generalizes |
| Product matching | Rules: Match exact SKU | ⚠️ Depends: Exact SKU = rules is better |
| Content moderation | Rules: List of banned words | ✅ Better: Detects context |
General rule: If there's linguistic variability → Embeddings. If it's exact (IDs, codes) → Rules.
Advanced use cases
1. Cross-lingual search (multilingual search):
# User searches in Spanish, finds docs in English:
query_es = "cómo instalar Python"
doc_en = "How to install Python on Windows"
# With a multilingual model (OpenAI, multilingual-SBERT):
emb_query_es = embed(query_es)
emb_doc_en = embed(doc_en)
similarity = cosine_similarity(emb_query_es, emb_doc_en) # → ~0.90 ✅
Application: Multilingual support without translating all the content.
2. Duplicate detection:
# Detect duplicate tickets:
ticket_1 = "I can't log in"
ticket_2 = "Error when signing in"
emb_1 = embed(ticket_1)
emb_2 = embed(ticket_2)
if cosine_similarity(emb_1, emb_2) > 0.90:
print("Duplicate tickets") # ✅
Application: Reduce redundant work in customer support.
3. Personalization:
# User profile = average embedding of items they liked:
user_liked_items = [item_1, item_2, item_3]
user_profile_emb = np.mean([embed(item) for item in user_liked_items], axis=0)
# Recommend items similar to the profile:
for item in catalog:
sim = cosine_similarity(user_profile_emb, embed(item))
if sim > 0.80:
recommend(item)
4. Anomaly detection:
# Detect anomalous logs:
normal_logs = ["User login successful", "Payment processed", ...]
normal_embeddings = [embed(log) for log in normal_logs]
avg_normal_emb = np.mean(normal_embeddings, axis=0)
# New log:
new_log = "Database connection failed 50 times"
new_log_emb = embed(new_log)
# If very different from the average → Anomaly
sim = cosine_similarity(new_log_emb, avg_normal_emb)
if sim < 0.60:
alert("Anomalous log detected")
Exercises
Exercise 1: Simple semantic search
Implement semantic search over 3 documents:
documents = [
"Python is a programming language",
"The cat sleeps on the couch",
"JavaScript is used in web development"
]
query = "A language for programming"
# Find the most relevant document
See solution
from openai import OpenAI
import numpy as np
import os
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
def get_embedding(text):
response = client.embeddings.create(
model="text-embedding-3-small",
input=text
)
return np.array(response.data[0].embedding)
def cosine_similarity(vec_a, vec_b):
return np.dot(vec_a, vec_b) / (np.linalg.norm(vec_a) * np.linalg.norm(vec_b))
documents = [
"Python is a programming language",
"The cat sleeps on the couch",
"JavaScript is used in web development"
]
query = "A language for programming"
# Embed documents
doc_embeddings = [get_embedding(doc) for doc in documents]
# Embed query
query_embedding = get_embedding(query)
# Calculate similarities
similarities = [
(i, cosine_similarity(query_embedding, doc_emb))
for i, doc_emb in enumerate(doc_embeddings)
]
# Sort
similarities.sort(key=lambda x: x[1], reverse=True)
# Result
print("Results:")
for rank, (doc_id, sim) in enumerate(similarities, 1):
print(f"{rank}. {documents[doc_id]} (score: {sim:.4f})")
Expected output:
Results:
1. Python is a programming language (score: 0.87)
2. JavaScript is used in web development (score: 0.75)
3. The cat sleeps on the couch (score: 0.58)
Exercise 2: Simple classifier
Classify an email into 2 categories (Technical or Billing):
categories = {
"Technical": ["The app doesn't work", "Error when logging in"],
"Billing": ["My invoice is wrong", "I want to cancel my subscription"]
}
new_email = "I can't access my account"
# Classify the email
See solution
# Embed categories (average of examples)
category_embeddings = {}
for category, examples in categories.items():
embeddings = [get_embedding(ex) for ex in examples]
category_embeddings[category] = np.mean(embeddings, axis=0)
# Embed the new email
email_embedding = get_embedding(new_email)
# Find the most similar category
similarities = []
for category, cat_emb in category_embeddings.items():
sim = cosine_similarity(email_embedding, cat_emb)
similarities.append((category, sim))
similarities.sort(key=lambda x: x[1], reverse=True)
print(f"Email: '{new_email}'")
print(f"Classified as: {similarities[0][0]} (score: {similarities[0][1]:.4f})")
Output:
Email: 'I can't access my account'
Classified as: Technical (score: 0.92)
Exercise 3: Recommendations
Recommend 2 similar products:
products = [
"Laptop for programming",
"Wireless mouse",
"Mechanical keyboard",
"4K monitor"
]
user_viewed = "Laptop for programming"
# Recommend 2 similar products (excluding the viewed one)
See solution
# Embed products
product_embeddings = {
prod: get_embedding(prod) for prod in products
}
# Embedding of the viewed product
viewed_embedding = product_embeddings[user_viewed]
# Calculate similarities
similarities = []
for prod, prod_emb in product_embeddings.items():
if prod == user_viewed:
continue # Exclude the same one
sim = cosine_similarity(viewed_embedding, prod_emb)
similarities.append((prod, sim))
# Sort and take top-2
similarities.sort(key=lambda x: x[1], reverse=True)
print("Recommendations:")
for rank, (prod, sim) in enumerate(similarities[:2], 1):
print(f"{rank}. {prod} (score: {sim:.4f})")
Expected output:
Recommendations:
1. Mechanical keyboard (score: 0.76)
2. 4K monitor (score: 0.72)
Summary
What you learned:
- ✅ Semantic Search: Search by meaning, not keywords
- ✅ RAG: Give external knowledge to LLMs
- ✅ Recommendations: Suggest similar items
- ✅ Classification: Categorize documents automatically
- ✅ Clustering: Group documents without supervision
Real use cases:
- Notion, Slack → Semantic search
- ChatGPT, Perplexity → RAG
- Netflix, Spotify → Recommendations
- Zendesk, Gmail → Classification
- Google News, Reddit → Clustering
When to use embeddings:
- ✅ Linguistic variability (synonyms, paraphrases)
- ✅ Semantic search
- ⚠️ Hybrid with keywords for a better result
Additional resources
- RAG Explained - Complete guide
- Semantic Search Tutorial - SBERT
- Recommendations with Embeddings - OpenAI
- Document Clustering - Scikit-learn
- Hybrid Search - Elasticsearch
In the next capsule
Capsule 06: Embeddings vs Keywords
You'll learn:
- BM25 (keyword matching) in detail
- When embeddings > keywords
- When keywords > embeddings
- Hybrid search (the best of both worlds)
- Practical implementation of the comparison
From use cases to architecture decisions.
Module 1 - Embeddings Deep Dive Guide Real applications that transform industries