Portfolio Projects ยท Project 1 of 10
Project 1: RAG Chatbot over PDFs with Citations
The most asked-about GenAI project in interviews. You'll build a chatbot that answers questions from a set of PDFs (policies, manuals, research papers), cites its sources and says "I don't know" when the answer isn't there. Then you'll measure its quality.
What you'll build
- Upload or point to a folder of PDFs, which are parsed, chunked, embedded and indexed.
- A chat UI that streams answers with clickable [source: file, page] citations.
- An evaluation script reporting retrieval recall@k and faithfulness on 30 test questions.
Architecture
PDFs โ loader (PyPDF / unstructured) โ splitter (800 tokens, 100 overlap) โ embeddings โ FAISS/Chroma
User question โ retriever (k=8) โ re-ranker (top 4) โ prompt with context + rules โ LLM โ answer + citations
โ logs (question, chunks, answer, latency)
Tech stack
Python, LangChain (LCEL), FAISS or Chroma, bge-small or OpenAI embeddings, an LLM (OpenAI / Groq / Ollama), FastAPI, Streamlit, RAGAS.
Step by step
- Ingest: load the PDFs with page numbers in the metadata; clean headers and footers.
- Chunk: a recursive splitter, about 800 tokens with 100 overlap; keep
sourceandpage. - Embed and index: build FAISS and persist it to disk.
- Retrieve: similarity search with k=8, then a cross-encoder re-ranker down to the top 4.
- Prompt: "Answer only from the context, cite [file:page], otherwise say you don't know."
- Serve: a FastAPI
/chatendpoint with streaming; Streamlit as the front end. - Evaluate: write 30 Q&A pairs, then compute recall@k and RAGAS faithfulness and answer relevancy.
- Iterate: try chunk sizes, hybrid search and re-ranking; record the scores in a table.
Starter code
from langchain_community.document_loaders import PyPDFDirectoryLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
docs = PyPDFDirectoryLoader("data/").load()
chunks = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=100).split_documents(docs)
db = FAISS.from_documents(chunks, HuggingFaceEmbeddings(model_name="BAAI/bge-small-en-v1.5")); db.save_local("index")
retriever = db.as_retriever(search_kwargs={"k": 4})
prompt = ChatPromptTemplate.from_template(
"Answer ONLY from the context. Cite sources as [file:page]. If unsure, say \"I don't know\".\n\n{context}\n\nQ: {q}")
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
def ask(q):
ctx = retriever.invoke(q)
c = "\n\n".join(f"[{d.metadata['source'].split('/')[-1]}:{d.metadata.get('page', 0) + 1}] {d.page_content}" for d in ctx)
return llm.invoke(prompt.format(context=c, q=q)).content
Deploy it
- Free options: Hugging Face Spaces (Streamlit), Render or Railway (FastAPI), or the Streamlit Community Cloud.
- Keep API keys in secrets / environment variables, never in code. Add a README with a GIF demo and the evaluation table.
Put it on your resume
- Built a RAG chatbot over 200+ PDFs using LangChain, FAISS and a cross-encoder re-ranker, answering with page-level citations and a refusal for out-of-scope queries.
- Improved retrieval recall@4 from 0.68 to 0.89 and faithfulness to 0.93 (RAGAS) through chunk-size tuning, hybrid search and re-ranking; deployed with FastAPI and Streamlit.
(Use your own real numbers from the evaluation step.)
Interview questions you'll get
- How did you choose chunk size and overlap? What happens if chunks are too small or too large?
- Why add a re-ranker? What is the difference between a bi-encoder and a cross-encoder?
- How do you stop hallucinations? How did you measure faithfulness?
- How would you scale to a million documents and keep the index fresh?
Practise these in Mock Interview โ RAG & Retrieval.
Stretch goals
- Hybrid BM25 + dense search with Reciprocal Rank Fusion.
- Conversation memory with question rewriting.
- Access control: filter retrieval by user role.
- A query-routing agent that decides when to retrieve.
๐ Add this project to my resume๐ค Practise in a mock interview๐ฅ Daily challenge๐ Certificates
Created by Ajeetkumar