A practical guide to keyword search, semantic search, BM25, embeddings, and when each retrieval strategy works best in a RAG pipeline
Introduction
In the previous tutorials of this RAG series, we covered what RAG is, why LLMs hallucinate, and how a RAG pipeline works.
Now we arrive at one of the most important components of the entire system:
Retrieval.
A RAG system is only as useful as the information it retrieves.
Imagine a user asks:
“What is the company’s parental leave policy for employees in Germany?”
Your knowledge base may contain thousands or millions of documents.
The system now has to answer a difficult question:
Which pieces of information should reach the LLM?
This is where retrieval comes in.
There are two major approaches:
- Sparse Retrieval — primarily based on words and lexical matching.
- Dense Retrieval — based on semantic meaning using embeddings.
At first glance, dense retrieval may seem like the obvious winner.
After all, embeddings can understand that:
"What is the leave policy?"and"How many vacation days do employees receive?"
are semantically related even though they use different words.
But sparse retrieval is far from obsolete.
In fact, keyword-based retrieval can outperform vector search in many real-world scenarios, especially when users search for:
- Product IDs
- Error codes
- Names
- Legal clauses
- Technical terms
- Exact phrases
- Rare entities
This is why many production RAG systems don’t choose between dense and sparse retrieval.
They use both.
By the end of this tutorial, you’ll understand exactly why.
Table of Contents
- What You’ll Learn
- Prerequisites
- The Retrieval Problem in RAG
- What Is Sparse Retrieval?
- TF-IDF: The Foundation of Traditional Search
- Understanding BM25
- Sparse Retrieval in Python
- What Is Dense Retrieval?
- How Embeddings Enable Semantic Search
- Dense Retrieval in Python
- Dense vs. Sparse Retrieval
- Where Sparse Retrieval Wins
- Where Dense Retrieval Wins
- Why Production RAG Uses Hybrid Search
- Building a Simple Hybrid Retriever
- Common Retrieval Mistakes
- Production Considerations
- Interview Questions
- Key Takeaways
- Related Tutorials
- Next Tutorial
- About the Author
What You’ll Learn
By the end of this tutorial, you’ll be able to:
- Understand the difference between dense and sparse retrieval.
- Explain why BM25 still matters in modern AI systems.
- Understand how embeddings enable semantic search.
- Build a simple BM25 retriever in Python.
- Build a vector-based semantic retriever.
- Compare the results of both approaches.
- Understand when keyword search outperforms embeddings.
- Build the foundation for hybrid search.
- Discuss dense vs. sparse retrieval in an AI or GenAI interview.
Prerequisites
You should have a basic understanding of:
- Python
- Machine learning concepts
- Text embeddings
- Vector databases
- Basic RAG architecture
You don’t need to know the mathematics behind Transformers to understand this tutorial.
The Retrieval Problem in RAG
Let’s start with a simple example.
Suppose your knowledge base contains these documents:
Document 1:Employees receive 20 days of annual leave.Document 2:The company provides parental leave for eligible employees.Document 3:Employees experiencing production error ERR_AUTH_401should verify their authentication token.
Now imagine three different queries.
Query 1
How many vacation days do employees get?
The words vacation and annual leave don’t exactly match.
A keyword-based system may struggle.
A semantic embedding model, however, can understand that the two phrases are related.
Query 2
How do I fix ERR_AUTH_401?
In this case, exact matching is extremely valuable.
The string:
ERR_AUTH_401
is not something we necessarily want to interpret semantically.
We want to find the exact technical identifier.
Sparse retrieval can perform extremely well here.
Query 3
What benefits are available for new parents?
The document might contain:
Parental leave is available for eligible employees.
Again, the exact words are different.
Dense retrieval has an advantage.
This gives us the central idea of the article:
Different queries require different retrieval strategies.
The Big Picture
Here is the fundamental difference.
USER QUERY
│
┌────────────┴────────────┐
│ │
▼ ▼
Sparse Retrieval Dense Retrieval
│ │
▼ ▼
Keyword Matching Semantic Matching
│ │
▼ ▼
BM25 Embeddings
│ │
└────────────┬────────────┘
│
▼
Relevant Documents
Sparse retrieval asks:
Which documents contain words related to the query?
Dense retrieval asks:
Which documents have a similar meaning to the query?
That difference has major implications for RAG.
What Is Sparse Retrieval?
Sparse retrieval represents documents using mostly zero-valued vectors.
Imagine a vocabulary containing:
annualleaveemployeeparentalvacationpolicy
A document:
Employees receive annual leave.
might be represented conceptually as:
annual → 1leave → 1employee → 1parental → 0vacation → 0policy → 0
So the vector becomes:
[1, 1, 1, 0, 0, 0]
Most values are zero.
Hence the name:
Sparse vector
Sparse retrieval traditionally relies on techniques such as:
- Boolean Search
- TF-IDF
- BM25
Among these, BM25 remains one of the most widely used ranking algorithms in search systems.
TF-IDF: A Quick Foundation
Before understanding BM25, it helps to understand TF-IDF.
TF-IDF stands for:
Term Frequency × Inverse Document Frequency
The basic intuition is simple.
A word should be important if:
- It appears frequently in a document.
- It is relatively rare across the entire collection.
For example:
theandis
appear almost everywhere.
They aren’t particularly useful for retrieval.
But a term like:
ERR_AUTH_401
might appear in only one document.
That makes it highly informative.
Conceptually:
Importance(term)=Frequency in document×Rarity across corpus
TF-IDF was foundational to traditional information retrieval, but BM25 improves upon some of its limitations.
Understanding BM25
BM25 is a ranking algorithm that estimates how relevant a document is to a query.
Its full mathematical formulation is:
f(q, D) × (k₁ + 1)
Score = IDF(q) × ─────────────────────────
f(q, D) + k₁ × (1 - b + b × |D| / avgDL)
Don’t worry about memorizing the equation.
The important intuition is much simpler.
BM25 considers:
1. Term Frequency
If a query term appears in a document, that increases relevance.
But BM25 prevents repeated occurrences from increasing the score indefinitely.
For example:
Python Python Python Python Python
shouldn’t automatically be ranked much higher than:
Python programming tutorial
BM25 handles this using saturation.
2. Inverse Document Frequency
Rare words are more informative.
For example:
"machine"
might appear in thousands of documents.
But:
"ERR_AUTH_401"
may appear in only one.
The rare term receives more importance.
3. Document Length Normalization
Long documents naturally contain more words.
Without normalization, they could receive an unfair advantage.
BM25 adjusts scores based on document length.
This is particularly important for knowledge bases containing documents of different sizes.
Sparse Retrieval Architecture
A simplified sparse retrieval system looks like this:
Documents │ ▼Tokenization │ ▼Inverted Index │ ▼┌──────────────────────────────┐│ annual → Document 1 ││ parental → Document 2 ││ ERR_AUTH_401 → Document 3 │└──────────────────────────────┘ Query │ ▼ Tokenization │ ▼ BM25 │ ▼ Ranked Documents
One of the major advantages of sparse retrieval is the inverted index.
Instead of comparing a query against every document, the search system can efficiently locate documents containing relevant terms.
Sparse Retrieval in Python
Let’s build a small BM25 retriever.
First, install the dependency:
pip install rank-bm25
Now create some documents.
documents = [ "Employees receive 20 days of annual leave.", "Eligible employees can apply for parental leave.", "Production error ERR_AUTH_401 indicates an invalid authentication token.", "Remote employees can work from home three days per week."]
BM25 expects tokenized documents.
tokenized_documents = [ document.lower().split() for document in documents]
Create the BM25 index:
from rank_bm25 import BM25Okapibm25 = BM25Okapi(tokenized_documents)
Now let’s search.
query = "How do I fix ERR_AUTH_401?"tokenized_query = query.lower().split()scores = bm25.get_scores(tokenized_query)for document, score in zip(documents, scores): print(f"{score:.2f} -> {document}")
The document containing the exact error code should receive a high score.
We can retrieve the top results.
top_documents = bm25.get_top_n( tokenized_query, documents, n=2)for document in top_documents: print(document)
Output:
Production error ERR_AUTH_401 indicates an invalid authentication token.
This is a good example of where lexical retrieval can be extremely effective.
What Is Dense Retrieval?
Dense retrieval takes a completely different approach.
Instead of representing documents using vocabulary positions, it uses an embedding model.
Consider:
Employees receive 20 days of annual leave.
An embedding model might convert it into:
[0.21, -0.54, 0.88, ..., 0.17]
Unlike sparse vectors, most dimensions contain non-zero values.
Hence:
Dense vector
Modern embedding models may produce vectors containing hundreds or thousands of dimensions.
The important part is not the individual numbers.
It’s the position of the text in a semantic vector space.
Semantic Similarity
Imagine a simplified two-dimensional embedding space.
VACATION
●
Query
●
Annual Leave
●
Authentication Error
The query:
How many vacation days do employees get?
may be close to:
Employees receive 20 days of annual leave.
even though they don’t share the same words.
This is the main advantage of dense retrieval.
It can capture:
- Synonyms
- Semantic relationships
- Similar intent
- Related concepts
- Different phrasing
Dense Retrieval Architecture
Documents │ ▼Embedding Model │ ▼Dense Vectors │ ▼Vector Database │ │ │User Query │ ▼Embedding Model │ ▼Query Vector │ ▼Similarity Search │ ▼Top-K Documents
Both the documents and query are converted into vectors using the same embedding space.
The system then calculates similarity.
Common similarity metrics include:
- Cosine Similarity
- Dot Product
- Euclidean Distance
Dense Retrieval in Python
Let’s build a simple semantic retriever.
Install the dependencies:
pip install sentence-transformers faiss-cpu
Load an embedding model.
from sentence_transformers import SentenceTransformermodel = SentenceTransformer("all-MiniLM-L6-v2")
Create our documents.
documents = [ "Employees receive 20 days of annual leave.", "Eligible employees can apply for parental leave.", "Production error ERR_AUTH_401 indicates an invalid authentication token.", "Remote employees can work from home three days per week."]
Generate embeddings.
document_embeddings = model.encode( documents, normalize_embeddings=True)
Now create a FAISS index.
import faissimport numpy as npdocument_embeddings = np.array( document_embeddings).astype("float32")dimension = document_embeddings.shape[1]index = faiss.IndexFlatIP(dimension)index.add(document_embeddings)
We use inner product search because the embeddings were normalized.
For normalized vectors, inner product corresponds to cosine similarity.
Search Using a Natural Language Query
Now let’s ask:
How many vacation days do employees get?
Notice that the document uses:
annual leave
rather than:
vacation days
Let’s search.
query = "How many vacation days do employees get?"query_embedding = model.encode( [query], normalize_embeddings=True)query_embedding = np.array( query_embedding).astype("float32")scores, indices = index.search( query_embedding, k=2)for score, idx in zip(scores[0], indices[0]): print(f"{score:.3f} -> {documents[idx]}")
Expected result:
Employees receive 20 days of annual leave.
This is semantic retrieval.
The system doesn’t require exact keyword overlap.
Dense vs. Sparse Retrieval
Now let’s compare the two approaches.
| Feature | Sparse Retrieval | Dense Retrieval |
|---|---|---|
| Primary mechanism | Keyword matching | Semantic similarity |
| Representation | Sparse vectors | Dense embeddings |
| Common algorithms | BM25, TF-IDF | Neural embedding models |
| Synonym handling | Limited | Strong |
| Exact keyword matching | Strong | Can be weaker |
| Rare terms | Strong | Can be inconsistent |
| Semantic understanding | Limited | Strong |
| Product IDs | Excellent | Potentially weaker |
| Error codes | Excellent | Potentially weaker |
| Natural language queries | Good | Excellent |
| Infrastructure | Mature and relatively simple | Requires embedding infrastructure |
| Updates | Easy to index | Requires embedding generation |
| Typical RAG usage | Often part of hybrid retrieval | Core semantic retrieval layer |
Neither approach is universally better.
The query determines what kind of retrieval is useful.
When Sparse Retrieval Wins
Sparse retrieval performs especially well when exact terms matter.
1. Error Codes
Example:
ERR_AUTH_401
The exact token is highly informative.
A user probably wants:
ERR_AUTH_401
not:
Some other authentication issue
2. Product IDs
Example:
SKU-8921-XL
Embedding models are not necessarily optimized to understand the importance of exact identifiers.
Keyword search is often more reliable.
3. Names
Suppose the user searches:
Johnathan R. Peterson
Exact lexical matching can be critical.
4. Legal and Technical Terms
Queries such as:
GDPR Article 17
or:
ISO 27001 Annex A
often benefit from exact lexical retrieval.
5. Rare Terms
Sparse retrieval benefits from IDF.
Rare terms naturally receive more importance.
This is useful in specialized enterprise knowledge bases.
When Dense Retrieval Wins
Dense retrieval shines when meaning matters more than exact wording.
1. Synonyms
Query:
How many vacation days do employees receive?
Document:
Employees receive 20 days of annual leave.
The wording differs, but the meaning is similar.
2. Natural Language Questions
Users rarely search using perfectly matching keywords.
They ask questions conversationally:
Can I work from home if my child is sick?
The document might say:
Employees may request temporary remote work under exceptional circumstances.
Dense retrieval has a better chance of connecting these concepts.
3. Conceptual Search
Query:
What happens if I forget my password?
Document:
Users can reset account credentials through the identity portal.
Again, the exact words don’t overlap much.
But the concepts are related.
The Core Trade-Off
The fundamental difference can be summarized like this:
Sparse Retrieval │ ▼"Find documents containing these words."Dense Retrieval │ ▼"Find documents discussing this idea."
Production search often needs both.
Why Hybrid Search Exists
Consider this query:
How do I fix error ERR_AUTH_401 in the login API?
This contains two different signals.
Semantic Intent
How do I fix an authentication problem?
Exact Identifier
ERR_AUTH_401
Dense retrieval is useful for understanding the broader intent.
Sparse retrieval is excellent at identifying the exact error code.
Hybrid search combines them.
User Query
│
┌──────────┴──────────┐
│ │
▼ ▼
BM25 Search Vector Search
│ │
▼ ▼
Keyword Score Semantic Score
│ │
└──────────┬──────────┘
│
▼
Score Fusion
│
▼
Ranked Documents
│
▼
LLM
This often provides more robust retrieval than relying on a single method.
Building a Simple Hybrid Retriever
Let’s combine BM25 and vector search.
First, define the documents.
documents = [ "Employees receive 20 days of annual leave.", "Eligible employees can apply for parental leave.", "Production error ERR_AUTH_401 indicates an invalid authentication token.", "Remote employees can work from home three days per week."]
Step 1: BM25 Retrieval
from rank_bm25 import BM25Okapitokenized_documents = [ document.lower().split() for document in documents]bm25 = BM25Okapi(tokenized_documents)
Search:
query = "How do I fix ERR_AUTH_401 authentication problems?"tokenized_query = query.lower().split()bm25_scores = bm25.get_scores( tokenized_query)
Step 2: Dense Retrieval
from sentence_transformers import SentenceTransformerimport numpy as npmodel = SentenceTransformer("all-MiniLM-L6-v2")document_embeddings = model.encode( documents, normalize_embeddings=True)query_embedding = model.encode( [query], normalize_embeddings=True)[0]dense_scores = np.dot( document_embeddings, query_embedding)
Now every document has:
BM25 Score+Dense Similarity Score
Step 3: Normalize the Scores
The two scoring systems may operate on completely different scales.
For a simple example, we can use min-max normalization.
def min_max_normalize(scores): scores = np.array(scores) return ( scores - scores.min() ) / ( scores.max() - scores.min() + 1e-8 )
Normalize both.
bm25_normalized = min_max_normalize( bm25_scores)dense_normalized = min_max_normalize( dense_scores)
Step 4: Combine the Scores
Now create a weighted combination.
alpha = 0.5hybrid_scores = ( alpha * dense_normalized + (1 - alpha) * bm25_normalized)
Sort the results.
ranked_indices = np.argsort( hybrid_scores)[::-1]for idx in ranked_indices: print( f"{hybrid_scores[idx]:.3f} -> " f"{documents[idx]}" )
This is a simple hybrid retrieval strategy.
In production, you might use more sophisticated approaches such as:
- Reciprocal Rank Fusion
- Learned score fusion
- Query-aware routing
- Cross-encoder reranking
We’ll explore these in future tutorials.
A Better Way to Think About Retrieval
Instead of asking:
Should I use dense or sparse retrieval?
Ask:
What kinds of queries do my users ask?
For example:
| Query Type | Recommended Strategy |
|---|---|
| Error codes | Sparse |
| Product IDs | Sparse |
| Exact names | Sparse |
| Natural language questions | Dense |
| Synonyms | Dense |
| Conceptual questions | Dense |
| Enterprise search | Hybrid |
| Technical documentation | Hybrid |
| Large production RAG | Hybrid + reranking |
Your retrieval strategy should be driven by your data and query distribution.
A Practical RAG Retrieval Pipeline
A more realistic production architecture might look like this:
User Query
│
▼
Query Processing
│
┌───────────┴───────────┐
│ │
▼ ▼
BM25 Retrieval Dense Retrieval
│ │
│ │
└───────────┬───────────┘
│
▼
Rank Fusion
│
▼
Top 20 Results
│
▼
Cross-Encoder
Reranking
│
▼
Top 5 Chunks
│
▼
Context Construction
│
▼
LLM
│
▼
Response
Notice something important.
The vector database is only one part of the retrieval system.
A production RAG pipeline may include:
Query understanding+Metadata filtering+Sparse retrieval+Dense retrieval+Rank fusion+Reranking+Context selection
This is why building reliable RAG systems is primarily an information retrieval problem, not simply an LLM problem.
Common Mistakes
Mistake 1: Assuming Vector Search Replaces BM25
A common mistake is:
Embeddings are newer ↓Therefore ↓Embeddings must be better
That’s not how retrieval works.
Exact matching remains extremely valuable.
Mistake 2: Using Only Similarity Scores
A high similarity score doesn’t guarantee relevance.
Different embedding models produce different score distributions.
Never assume:
0.80 = relevant0.60 = irrelevant
without evaluating the model on your own dataset.
Mistake 3: Ignoring Metadata
Suppose your knowledge base contains:
HR Policy 2024HR Policy 2025HR Policy 2026
A semantically relevant result may still be outdated.
Apply filters such as:
{ "country": "Germany", "document_type": "HR Policy", "version": "2026"}
Retrieval should combine:
Semantic relevance+Keyword relevance+Metadata constraints
Mistake 4: Retrieving Too Many Documents
A common approach is:
Top 100 documents ↓Send everything to the LLM
This increases:
- Token cost
- Latency
- Noise
- Risk of distracting the model
The goal is not:
Retrieve the most information.
The goal is:
Retrieve the most relevant information.
Mistake 5: Choosing an Embedding Model Without Evaluation
Don’t choose an embedding model simply because it is popular.
Evaluate it using:
- Domain-specific queries
- Expected user questions
- Retrieval recall
- MRR
- NDCG
- Latency
- Cost
The best model depends on your data.
Production Considerations
A simple local FAISS example is useful for learning.
Production systems introduce additional requirements.
1. Metadata Filtering
Your retriever may need to filter by:
UserTenantDepartmentCountryDocument VersionDatePermissions
Retrieval without authorization controls can become a security problem.
2. Hybrid Retrieval
Instead of choosing one retrieval strategy, production systems often combine:
BM25+Dense Retrieval+Metadata Filtering+Reranking
3. Query Routing
Not every query needs the same retrieval pipeline.
For example:
"ERR_AUTH_401"
could trigger stronger sparse retrieval.
While:
"What should I do if I can't log in?"
could prioritize semantic retrieval.
A query classifier or heuristic can dynamically choose the retrieval strategy.
4. Caching
Repeated queries can reuse:
- Query embeddings
- Retrieval results
- Generated answers
For example:
"What is the leave policy?"
may be asked thousands of times.
Caching can significantly reduce cost and latency.
5. Reranking
Initial retrieval optimizes for recall.
You might retrieve:
Top 50 candidates
Then use a more expensive model to rerank:
Top 50 ↓Cross-Encoder ↓Top 5
This allows the system to combine speed and accuracy.
How to Evaluate Dense vs. Sparse Retrieval
You shouldn’t decide based only on intuition.
Build a test dataset.
Query:"How many vacation days do employees receive?"Relevant Document:"Employees receive 20 days of annual leave."
Create dozens or hundreds of similar examples.
Then measure each system.
Important metrics include:
Recall@K
Did the correct document appear in the top K results?
Recall@5
asks:
Was the correct document found in the top five results?
MRR — Mean Reciprocal Rank
MRR considers where the first correct result appears.
For example:
Correct result at rank 1 → 1.0Correct result at rank 2 → 0.5Correct result at rank 5 → 0.2
Higher is better.
NDCG
NDCG is useful when documents have different levels of relevance.
For example:
Highly RelevantRelevantSomewhat RelevantIrrelevant
This becomes valuable when evaluating more complex search systems.
Interview Questions
1. What is the difference between dense and sparse retrieval?
Answer:
Sparse retrieval primarily relies on lexical matching between query terms and document terms. Techniques such as BM25 represent documents using high-dimensional sparse vectors. Dense retrieval uses neural embedding models to represent queries and documents as dense vectors and retrieves information based on semantic similarity.
2. When would you choose sparse retrieval over dense retrieval?
Answer:
I would favor sparse retrieval when exact lexical matches are important, such as error codes, product IDs, names, legal clauses, or rare technical terms. Sparse retrieval benefits from exact matching and term rarity through mechanisms such as inverse document frequency.
3. Why can dense retrieval outperform BM25?
Answer:
Dense retrieval captures semantic relationships between text. It can retrieve documents containing synonyms or conceptually similar phrases even when there is little or no keyword overlap between the query and document.
4. Why is BM25 still useful in modern RAG systems?
Answer:
Embedding models can lose important lexical information, particularly for exact identifiers, rare entities, and technical terms. BM25 provides strong lexical matching and often complements dense retrieval, which is why hybrid retrieval is commonly used.
5. How would you combine dense and sparse retrieval?
Answer:
I would retrieve candidate documents from both systems and combine their rankings using a strategy such as weighted score fusion or Reciprocal Rank Fusion. The combined candidates could then be passed through a cross-encoder reranker before selecting the final context for the LLM.
6. What would you debug if dense retrieval returns irrelevant documents?
Answer:
I would investigate the embedding model, chunking strategy, query formulation, similarity metric, metadata filters, indexing pipeline, and whether the model was evaluated on the specific domain. I would also compare retrieval quality against BM25 to understand whether the issue is semantic representation or the underlying data.
7. Why shouldn’t you rely on a fixed similarity threshold?
Answer:
Similarity scores are model-dependent and dataset-dependent. A score of 0.8 from one embedding model does not necessarily represent the same relevance level as 0.8 from another model. Thresholds should be calibrated using an evaluation dataset.
Key Takeaways
Dense and sparse retrieval solve different problems.
Sparse Retrieval ↓Best at finding exact words.Dense Retrieval ↓Best at finding similar meanings.
The most important comparison is:
| Use Case | Better Starting Point |
|---|---|
| Error codes | Sparse |
| Product IDs | Sparse |
| Exact names | Sparse |
| Rare technical terms | Sparse |
| Synonyms | Dense |
| Natural language questions | Dense |
| Conceptual search | Dense |
| Enterprise RAG | Hybrid |
| Production search | Hybrid + reranking |
The biggest lesson is:
Dense retrieval did not replace sparse retrieval. It expanded what retrieval systems can do.
The strongest RAG systems combine the strengths of both approaches.
A modern retrieval pipeline often looks like:
Query │ ├── BM25 ───────────┐ │ │ └── Embeddings ─────┤ ▼ Rank Fusion │ ▼ Reranking │ ▼ Best Context │ ▼ LLM
And that leads directly to the next important question:
How does BM25 actually work, and why does a search algorithm developed decades ago still power modern AI systems?
Related Tutorials
This article is part of the RAG Fundamentals content cluster.
- What Is RAG?
- Why LLMs Hallucinate
- How RAG Works
- Dense vs. Sparse Retrieval ← You are here
- BM25 Explained
- Hybrid Search
- RAG Chunking Strategies
- Embeddings Explained
- Cross-Encoder Reranking
- Parent-Child Retrieval
- Multi-Query Retrieval
- Self-RAG
- Corrective RAG
- Graph RAG
- Agentic RAG
- RAG Evaluation
- Production RAG
Next Tutorial
BM25 Explained: How Search Engines Rank Documents Before Your LLM Sees Them
In the next tutorial, we’ll go deeper into BM25.
We’ll cover:
- Term Frequency
- Inverse Document Frequency
- Document length normalization
- The BM25 formula
- BM25 parameters
- Python implementation
- BM25 vs. TF-IDF
- BM25 limitations in RAG
About the Author
Ved Prakash is a Senior Data Scientist and AI Engineer with experience in Machine Learning, Deep Learning, Data Engineering, and Generative AI.
His work focuses on building practical and production-oriented AI systems using technologies such as:
- Large Language Models
- Retrieval-Augmented Generation
- AI Agents
- LangGraph
- Vector Databases
- Python
- PySpark
- Databricks
- Cloud and MLOps
He writes practical tutorials and technical deep dives on GeekyCodes, covering:
Generative AI · RAG · LLMs · AI Engineering · Machine Learning · Data Engineering
The goal is simple:
Understand how modern AI systems actually work — not just how to call a framework.
Next in the series: BM25 Explained →