An engineer insists you need LangChain to do RAG. Refute that claim concretely. Describe the minimum viable RAG pipeline and then say when LangChain (or LlamaIndex) is actually worth adopting on top of it.
Minimal RAG is four steps (embed, retrieve, format, complete) in 80 lines with no framework.
Picture a kid claiming you need a kitchen to make a sandwich. You point out that bread, peanut butter, and a knife do the job. They are right that the kitchen helps once you want to make ten different sandwiches with toasted bread and a side soup. But the kitchen is not the sandwich. RAG is the same. The 'kitchen' is the framework. The 'sandwich' is the four steps. Confusing the two leads teams to import five megabytes of code to do something the standard library could do in a screen of code.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
The claim 'you need LangChain to do RAG' is a textbook example of confusing framework popularity with framework requirement. RAG predates LangChain by years and runs in production at many companies without it. At the same time, frameworks are not useless. They are worth adopting at specific complexity thresholds. A sound view holds both ideas: the necessity claim is false, and the framework repays its cost in specific cases.
Four complexity classes move the decision toward framework adoption, and the production heuristic is piecemeal adoption.
The minimum viable RAG pipeline
Four steps span the whole pattern. Embed the query: call your embedding model (text-embedding-3-small is a cost-effective default, bge-large-en-v1.5 for self-hosted) and get a fixed-dimensional vector. Retrieve top-k chunks: send that vector to your vector store and get back the k nearest neighbors with their metadata. Vector stores in common production use include Pinecone (managed, easiest to start with), pgvector (Postgres extension, no new infrastructure), Qdrant (open source, strong filtering), and Weaviate (open source, hybrid search built in). Format the retrieved chunks into a prompt: a template that includes the question, the retrieved chunks (often numbered for citation), and any system instructions about not making things up. Complete by calling the chat model: pass the prompt to the model SDK and return the response, often with citations parsed back to the chunk numbers.
Written directly in Python with the OpenAI SDK plus the Pinecone client, this is about 30 lines of pipeline code plus a few lines of setup. With chunking, ingestion, and error handling it grows to about 80 lines. It works in production. It is debuggable because the stack is shallow. It is fast because there are no framework abstractions between user code and the model. It is maintainable because anyone reading it understands what each line does without consulting framework documentation.
Nothing about this pipeline requires LangChain or LlamaIndex. The misconception that it does comes from an imbalance in marketing. Framework tutorials and blog posts far outnumber 'here is the 30 lines you can write yourself' tutorials. So engineers absorb the framework-shaped version as the standard approach.
Situations where this technique stops working.
2–4 min · Everything important, quickly.
# Minimum viable RAG: no framework, ~30 lines
from openai import OpenAI
from pinecone import Pinecone
client = OpenAI()
index = Pinecone().Index('my-index')
def rag(question: str, k: int = 5) -> str:
# 1. Embed
q_vec = client.embeddings.create(
model='text-embedding-3-small', input=question
).data[0].embedding
# 2. Retrieve
matches = index.query(vector=q_vec, top_k=k, include_metadata=True).matches
chunks = [m.metadata['text'] for m in matches]
# 3. Format
context = '\n\n'.join(f'[{i+1}] {c}' for i, c in enumerate(chunks))
prompt = f'Answer using ONLY the context. If unsure, say so.\n\nContext:\n{context}\n\nQuestion: {question}'
# 4. Complete
resp = client.chat.completions.create(
model='gpt-4o-mini',
messages=[{'role': 'user', 'content': prompt}],
)
return resp.choices[0].message.content
print(rag('What is the company refund policy?'))Real products, models, and research that use this idea.
- Lewis et al. published retrieval-augmented generation in 2020. LangChain's first release came in October 2022
- pgvector adds vector similarity search to PostgreSQL, so a RAG retriever can be one SQL query in an existing database
What an interviewer would ask next. Try answering before peeking at the approach.
QAt what point in a project's lifecycle does adopting a framework become net-positive?
When the second or third complexity class shows up. One hybrid retrieval can be hand-rolled. With one hybrid retrieval plus one router plus one synthesizer strategy, the framework's pre-built primitives start to repay their cost. Re-evaluate at each major feature addition.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Mistaking framework popularity for framework requirement. The framework being widely used does not mean the underlying technique depends on it.
60 second bullets to scan on the way to the call.
The four canonical steps of minimal RAG
Concrete examples of vector stores used in production (Pinecone, pgvector, Qdrant, Weaviate)
Primary sources. Browse if you want the original framing.
Same topic, related formats. Practice these next.