Retrieval augmented generation has become the default response to every document problem. Several cheaper options are worth ruling out first.
A team has documents. Someone needs to get answers out of them. Within about ten minutes, the plan is a vector database, an embedding model, a chunking strategy, and a retrieval pipeline. Nobody asked whether the problem actually requires any of that.
This post is not an argument against retrieval augmented generation. RAG is a good technique and there are problems where nothing else will do. The argument is narrower: RAG has become the default, and defaults do not get examined. It carries real operational cost, and a meaningful share of the systems built with it would work better as a search box, a SQL query, or a text file pasted into a prompt.
One definition first. Retrieval augmented generation means: before you ask the language model a question, you fetch some relevant text from your own data and paste that text into the prompt alongside the question. The model then answers using the material you supplied. "Retrieval" is the fetching step. "Augmented generation" is the model answering with the fetched text in front of it.
The usual implementation fetches that text by semantic search. Documents get split into chunks, each chunk is converted into a vector (a list of numbers representing its meaning), and those vectors go into a vector store, a database built to find the vectors closest in meaning to your question. That machinery is what most people mean when they say "we built RAG."
What follows is a ladder of increasing complexity. Stop at the first rung that solves the problem.
Start with the most basic question, and be honest about the answer: does the user want to find a document, or ask a question?
These are different needs and they get conflated constantly. Someone looking for "the Q3 vendor contract" does not want a generated paragraph summarising the contract. They want the contract. A search result list with a good filter UI gives them the file in one click. A RAG pipeline gives them a paragraph that may or may not be accurate, and they still have to open the file to be sure.
Full text search is fast, cheap, has no per query model cost, and is predictable, which matters more than people credit. When a keyword search returns nothing, the user understands exactly what happened and adjusts their words. When a retrieval system returns a wrong but fluent answer, the user has no idea anything went wrong.
Reach for search first when:
That last point deserves weight. Semantic search is weaker at exact identifiers than plain keyword matching. If your users search for strings like ERR_5521, embeddings are the wrong tool even for the retrieval step.
If the answer lives in structured data, query it, do not embed it.
This sounds obvious written down, and it is violated all the time. Teams take rows from a transactions table, turn each row into a sentence, embed it, and load it into a vector store so users can "ask questions about the data." Then they discover that "how many orders shipped late last month" returns whichever rows happened to be semantically nearest, which is not a count. It is an impression.
Aggregation, filtering, joins, and sorting are what relational databases have been optimised for over decades. Nearest neighbour search cannot do them, and pretending otherwise produces confidently wrong numbers.
The right pattern here is usually natural language to SQL: let the model write a query against a well defined schema, run the query, and return real results.
-- The model generates this. The database computes the answer.
SELECT COUNT(*)
FROM orders
WHERE shipped_at > promised_at
AND order_date >= '2026-01-01'
AND order_date < '2026-02-01';The model is doing translation, not arithmetic. The count comes from the database, so it is correct by construction. This approach has its own failure modes, mostly ambiguous schemas, which is why it works best over a curated view with clear column names rather than raw production tables.
A rule of thumb: if the answer could be a number in a report, it belongs in a query.
The option most often skipped: when the corpus is small and stable, send the whole thing to the model.
Long context models can accept a substantial amount of text in a single prompt. The exact limits move constantly and vary by model, so check that on the day you build rather than treating it as fixed. The point is directional: a corpus that would have been unthinkable to pass whole a few years ago is now often reasonable.
The advantage is not just simplicity. Retrieval is a lossy filter, and skipping it removes an entire class of failure. If the model has every document in front of it, it cannot fail to retrieve the right chunk, because there was no retrieval step to get wrong.
What this deletes from the system:
| Component | RAG pipeline | Full context |
|---|---|---|
| Chunking logic | Required, needs tuning | None |
| Embedding model | Required, plus a bill | None |
| Vector store | Deployed and operated | None |
| Re-indexing on change | Required | Resend the text |
| Retrieval quality tuning | Ongoing | Not applicable |
| Cost driver | Storage, embeddings, queries | Input tokens |
The trade is real. You pay in input tokens on every call, and long prompts add latency. Prompt caching helps when the document set is stable. The honest summary is that this rung fails at scale and works well below it.
A good candidate: a company handbook, a product spec, a set of policy documents. Bounded, changes monthly at most, everyone sees the same version.
Look at the question distribution before you build anything that answers questions live.
Real usage is rarely uniform. A support tool typically gets the same small set of questions over and over, phrased differently, with a long tail of genuine novelty behind them. If a large share of traffic is a known set of repeated questions, you do not need to retrieve anything at request time. You need an FAQ, generated once and served.
The pattern:
For the questions it covers, this beats live retrieval on almost every axis. It is faster and cheaper, since there is no model call. Above all it is reviewable: a person has read the answer before a user ever sees it, which is not true of anything generated on demand. In a high stakes domain, that property alone can decide the design.
Fine tuning is often presented as the alternative to RAG, which sets up the comparison badly. They solve different problems, and the distinction is the most useful thing to hold onto here:
Fine tuning teaches behaviour. Retrieval supplies facts.
Fine tuning means continuing to train a model on your own examples so it internalises a pattern. It works well for:
It works poorly for facts. Facts baked into weights cannot be updated without retraining, cannot be cited, and cannot be restricted per user. If your requirement is "the model should answer in our house format," fine tuning is a strong candidate. If it is "the model should know last Tuesday's policy change," it is the wrong tool.
The fair statement of the other side. RAG is the correct answer when several of these hold at once:
Large plus changing plus permissioned plus cited is the real home ground for RAG. It is a genuinely hard problem and retrieval is a genuinely good answer to it. I would reach for RAG when at least three of those five apply, and treat one alone as a weak signal.
The reason to rule out the cheaper rungs first is that RAG is not a library you import. It is a system you own, permanently.
None of these is a reason to avoid RAG. They are reasons to be sure you need it.
Work down and stop at the first match.
Does the user want the document itself?
-> Search with filters.
Is the answer computed from structured data?
-> SQL, or natural language to SQL over a defined schema.
Is the corpus small and stable?
-> Put it all in the context window.
Is it the same handful of questions repeatedly?
-> Precompute answers, review them, serve them.
Is the need style, format, or classification rather than facts?
-> Fine tune.
Large, changing, permissioned, and needs citations?
-> RAG. Build it properly.Most document problems exit this list before the last line.
RAG became the default because it arrived at the moment everyone had documents and a language model, and it fit the problem well enough to stop the search. That is how defaults form. They are rarely wrong so much as unexamined.
The ladder is the useful habit. Ask what the user actually wants, whether the data is structured, how big and how stable the corpus is, and whether the same questions repeat. Each answer either eliminates a rung or confirms it. By the time you reach the top, you either have a much simpler system than you expected, or a clear reason for the complexity you are taking on.
Both outcomes are wins. The failure mode is skipping the ladder entirely and finding out much later that a vector store, an ingestion pipeline, and an evaluation suite were all standing in for a search box.
Build the simplest thing that cannot be talked out of the right answer.
Coming soon.