Zero-shot โ just ask. No examples given, model relies purely on pre-trained knowledge + instruction. Fast, cheap, but weaker on tricky/unfamiliar formats.
Few-shot โ show 2โ5 example (input โ output) pairs inside the prompt before the real question. Model pattern-matches the desired format/style. Great for niche formatting, classification labels, tone control.
Chain-of-Thought (CoT) โ ask the model to "think step by step" before giving the final answer. Forces intermediate reasoning tokens โ big accuracy gains on math/logic/multi-hop questions.
ReAct (Reason + Act) โ interleaves reasoning with tool calls: Thought โ Action (call a tool/API) โ Observation (tool result) โ repeat โ Final Answer. This is the backbone of most modern agents.
fig 1 โ from zero-shot to agentic ReAct loops
interview line: "CoT improves reasoning; ReAct grounds reasoning in real tool outputs โ that's what turns an LLM into an agent"
โกEmbeddings & Vector Databases
An embedding = a piece of text squeezed into a dense numeric vector where "semantic closeness" โ "geometric closeness." Vector DBs store millions of these and answer: "give me the k nearest vectors to this query."
100% accurate, but slow / doesn't scale past ~1M vectors
IVF
k-means cluster centroids; only probe nearest few clusters
Much faster; accuracy depends on nprobe (clusters searched)
HNSW
Multi-layer proximity graph; greedy hop from sparse top layer down to dense bottom layer
Very fast + high recall; more memory, slower to build/insert
โขRAG Pipeline Architecture
RAG = Retrieval-Augmented Generation: fetch relevant external knowledge at query time and feed it to the LLM, instead of relying only on frozen training-time knowledge.
Chunking strategies โ how you split docs before embedding decides retrieval quality:
Fixed-size โ split every N tokens (e.g., 512) with some overlap; simple, but can cut mid-thought.
Recursive / structure-aware โ split on paragraph โ sentence boundaries, respecting headings; keeps semantic units intact.
Semantic chunking โ split where embedding similarity between adjacent sentences drops, i.e. where "topic" actually shifts.
Sliding window overlap โ small overlap between chunks (~10-20%) so context isn't lost right at a chunk boundary.
Why re-ranking? Vector search is fast but approximate โ it optimizes recall over a huge corpus using cheap similarity. A re-ranker (usually a cross-encoder that jointly reads query+passage) is slower but far more accurate, applied only to the top-k shortlist to pick the best few for the final prompt.
๐ RAGAS evaluation framework
Faithfulness โ is the generated answer actually grounded in the retrieved context (no hallucinated facts)?
Answer Relevance โ does the answer actually address the user's question (not just faithful, but on-topic)?
(also commonly paired with) Context Precision / Context Recall โ did retrieval fetch the right, and only the right, passages?
gotcha: faithfulness โ relevance โ an answer can be 100% grounded in context yet not actually answer the question asked!
โฃCustomization Decision Framework
Interview favorite: "Would you prompt-engineer, RAG, fine-tune, or pre-train?" โ answer by asking what's actually missing.
fig 5 โ pick the cheapest lever that actually fixes the gap
PEFT / LoRA / QLoRA intuition โ full fine-tuning updates all model weights (huge, expensive, needs lots of GPU memory). PEFT (Parameter-Efficient Fine-Tuning) freezes the base model and trains a tiny number of extra parameters instead.
LoRA โ freeze original weight matrix W; learn a small "correction" as two tiny low-rank matrices AยทB added on top (W + AยทB). Only A, B are trained โ a fraction of the parameters, so it's cheap and the adapter is a small file you can swap in/out.
QLoRA โ same idea, but the frozen base model is quantized to 4-bit first to shrink memory further, then LoRA adapters (kept in higher precision) are trained on top โ lets you fine-tune huge models on a single consumer GPU.
one-liner: "LoRA = train a small side-patch instead of the whole model; QLoRA = do that on a compressed (4-bit) base model to fit on less GPU"
โคModel Compression โ Quantization
Quantization = storing weights with fewer bits โ smaller model, faster inference, small accuracy loss.
fig 6 โ the precision/size/speed trade-off ladder
FP16 / BF16 โ the default for GPU training/inference; halves memory vs FP32 with almost no quality loss.
INT8 โ weights mapped to 256 discrete levels; common "safe" compression for serving on cheaper hardware.
INT4 โ 16 discrete levels; aggressive, needs careful calibration (e.g. GPTQ/AWQ) to avoid quality collapse โ but lets 7Bโ70B models run on consumer GPUs / even CPUs.
GGUF โ a file format (used by llama.cpp) packaging quantized weights (various bit-widths) + metadata + tokenizer into one portable file for easy local/CPU inference โ not a quantization method itself, but how quantized models are shipped and loaded.
โฅTooling Landscape
LangChain
LlamaIndex
Core focus
General orchestration โ chains, agents, tool-calling, memory, many integrations
Data-centric โ ingesting, indexing, and retrieving your documents efficiently
Mental model
"Lego blocks" to wire an LLM to tools, APIs, and multi-step logic/agents
"Smart librarian" โ specializes in turning messy docs into query-ready indexes
Two phases: offline indexing (once) and online query (every request).
# ---- OFFLINE: build the index ----for doc in corpus:
chunks = chunk_document(doc, size=512, overlap=50)
for chunk in chunks:
vector = embed_model.encode(chunk.text)
vector_db.upsert(id=chunk.id, vector=vector,
metadata={text: chunk.text, source: doc.id})
# ---- ONLINE: answer a user query ----defrag_answer(user_query):
q_vector = embed_model.encode(user_query)
# 1. Retrieve โ cast a wide, cheap net
candidates = vector_db.search(q_vector, top_k=20)
# 2. Re-rank โ slow but precise cross-encoder scoring
scored = [(c, reranker.score(user_query, c.text)) for c in candidates]
top_chunks = sort_desc(scored)[:5]
# 3. Synthesize context + prompt
context = join([c.text for c in top_chunks], sep="\n---\n")
prompt = build_prompt(system=RAG_SYSTEM_PROMPT,
context=context, question=user_query)
# 4. Generate
answer = llm.generate(prompt)
# 5. (optional) Evaluate before returning / logging
metrics = ragas_eval(question=user_query, answer=answer,
context=top_chunks) # faithfulness, relevancereturn answer, metrics
๐งฉ why each step earns its place
Retrieve wide (k=20) โ vector search alone is imprecise; over-fetch to protect recall.
Re-rank narrow (โ5) โ cross-encoder is too slow to run on the whole corpus, but cheap on 20 candidates; boosts precision right before it matters most.
Synthesize โ dedupe/order chunks, respect the LLM's context window, cite sources if needed.
Evaluate โ RAGAS-style scoring in the loop (or offline on a test set) catches hallucination/off-topic drift before it ships.