System Design
Last updated on

RAG Is Not Enough: Designing Production-Grade Agentic RAG


Retrieval-Augmented Generation (RAG) was the first honest answer to a hard problem: large language models do not know your documents, your tickets, or your policies. You embed the corpus, retrieve a few chunks, stuff them into the prompt, and generate. Demos look magical. Production often looks like a polite, well-cited hallucination.

This post is for teams who already shipped “simple RAG” and hit a wall. We will walk through where naive RAG fails, where Agentic RAG actually rescues the workflow, a side-by-side of Traditional vs Agentic RAG across storage, embeddings, retrieval, and chunking, then the main components of a production-grade design — plus a few mental models that make the architecture click.

What naive RAG actually is

Classic RAG is a one-shot pipeline:

User question
    → embed query
    → top-k similar chunks
    → LLM generates answer (with optional citations)

There is no planner. There is no second look. The retriever does not know if it retrieved the wrong policy version, a table split across two chunks, or a paragraph that is semantically close but operationally useless.

That loop is enough when:

  • The question maps to one or two passages
  • Documents are clean, current, and well chunked
  • The user asks “what does the docs say?” not “do the thing”

It is not enough when the job is multi-hop, time-sensitive, tool-backed, or high-stakes.

Problems with RAG systems (and when simple RAG does not solve them)

1. Semantic similarity is not task relevance

The vector store returns neighbors in embedding space. Your user asked for the refund policy that applies to enterprise contracts signed after March 2025. The nearest chunks may be a blog post about refunds, an old FAQ, and a marketing page that uses similar words.

Simple RAG has no way to say: filter by document type, effective date, and customer tier, then verify the clause against the contract metadata. Similarity ranked the wrong neighborhood.

Fails when: legal, policy, SKU, versioned SOPs, multi-tenant knowledge.

2. One retrieve cannot answer multi-hop questions

“Which vendor that supplies part X also had a P1 incident last quarter, and what was the workaround?” needs entity linking, then incident lookup, then runbook retrieval. One embedding of the full question usually retrieves a mush of vendor bios and unrelated incident write-ups.

Fails when: investigations, root-cause analysis, “compare A and B using facts from three systems.”

3. Chunking destroys the thing you needed

Tables, numbered procedures, API request/response pairs, and “if / else” policy trees die when you slice every 512 tokens with overlap. The model sees half a table or step 3 without steps 1–2. Simple RAG then “fills in” the missing rows.

Fails when: financial tables, configuration matrices, clinical protocols, runbooks.

4. Stale indexes look authoritative

RAG answers with the tone of a librarian even when the index was built six weeks ago and the wiki moved. There is no freshness check, no source-of-truth tool call (CRM, ticketing, feature flag), and no conflict detection when two chunks disagree.

Fails when: pricing, inventory, on-call status, “what is the current SLA?”

5. The user question is the wrong query

People type goals, not retrieval keys: “Help me onboard this customer like last time.” Simple RAG embeds that sentence. A useful system would rewrite into: account id, playbook name, last similar deal, required security questionnaire.

Fails when: vague tickets, voice transcripts, messy chat, multilingual paraphrases.

6. Retrieval cannot act

Even a perfect citation does not create a Jira ticket, book a change window, or query live SQL. Naive RAG stops at prose. Many production questions are workflows.

Fails when: “draft and file,” “check then escalate,” “update the CRM after you confirm.”

7. No self-correction when the context is empty or contradictory

If top-k is junk, the model still answers. If two chunks conflict, it averages them in language. There is no loop: retrieve → grade → rewrite query → retrieve again → refuse if still weak.

Fails when: sparse corpora, overlapping product lines, ambiguous acronyms.

8. Observability is a prompt dump

You cannot tell whether a bad answer was embedding drift, a bad chunk, a missing ACL, or the generator ignoring the context. Simple RAG gives you a black box with a vector ID.

Fails when: regulated industries, customer-facing SLAs, cost control.

Where Agentic RAG came to the rescue

Agentic RAG treats retrieval as a tool the agent can call many times, not as a fixed first step. An orchestrating model (or a small planner) decides whether to retrieve, what to retrieve, which corpus or API, when to stop, and when to use a non-RAG tool instead.

Below are scenarios where that loop simplified a problem simple RAG could not close.

Scenario A: Ambiguous support ticket → resolved with query rewriting + graders

A user writes: “It still doesn’t work after the update.” Naive RAG pulls random troubleshooting pages. Agentic RAG:

  1. Classifies product + version from ticket metadata
  2. Rewrites queries (“error code from logs,” “known issue after 2.4.1”)
  3. Retrieves, then a document grader drops off-version chunks
  4. If confidence is low, it asks one clarifying question or pulls the last three related tickets

The “solution” is not a smarter embedding. It is control flow around retrieval.

Scenario B: Contract + live CRM (hybrid retrieval)

Sales asks: “Can we offer 90-day payment terms to Acme?” Policy lives in a PDF; Acme’s tier and outstanding AR live in the CRM. Simple RAG only sees the PDF and invents Acme’s status. Agentic RAG retrieves the clause, calls the CRM tool, and grounds the answer in both. One pipeline became a short plan: retrieve policy → fetch account → apply rule.

Scenario C: Multi-hop incident investigation

“Did the same misconfig hit any other region?” Naive RAG retrieves a single postmortem. Agentic RAG walks: extract config key → search logs / graph of services → retrieve runbooks for affected services → summarize with citations. Each hop is a new retrieval or tool call, not a bigger k.

Scenario D: Tables and procedures that refused to chunk

A finance bot needed full rate cards. Naive RAG sliced columns apart. Agentic RAG detects “this is tabular”, retrieves parent document + table object (or SQL over a structured extract), and only then generates. Chunking strategy became a decision, not a global constant.

Scenario E: Conflicting sources and “I don’t know”

Two wikis disagree on a deprecation date. Simple RAG blends them. Agentic RAG flags conflict, retrieves source metadata (last updated, owner), and either prefers the system of record or refuses with both links. Users trust a bot that stops more than one that smooths.

Scenario F: From answer to action

“Open a Sev-2 if the error budget is burned.” Retrieval finds the error-budget policy; a metrics tool reads burn; a ticketing tool files only if the policy matches. Simple RAG would have written a nice paragraph and done nothing. Agentic RAG collapsed “read + decide + act” into one agent run with an approval gate.

Extra use cases where Agentic RAG helps

Use caseWhy naive RAG strugglesWhat the agent adds
Internal research assistantQuestions span wiki + tickets + SlackRoutes per source, cites, follows threads
Codebase Q&ANeed file + symbol + recent PRRepo tools + semantic + grep, not only embeddings
Healthcare / policy QAMust not mix patient cohorts or guideline yearsMetadata filters, graders, mandatory citations
Personalized learningNext explanation depends on what the user already sawSession memory + targeted retrieve of the next concept
Analytics copilot“Why did revenue drop?” is not a documentSQL/BI tools first; docs only for definitions
Multi-tenant SaaS helpEmbeddings leak across customers if ACLs are lateRetrieve-as-tool with tenant filters on every call
On-call copilotNeeds live status + runbookMix telemetry APIs with RAG; replan on new alerts

The pattern is the same: retrieval is necessary, not sufficient. Agency is the missing control plane.

Traditional RAG vs Agentic RAG (the retrieval stack)

TopicTraditional RAGAgentic RAG
StorageOne vector index (sometimes + metadata). Treats the corpus as a static bag of chunks.Multiple stores as tools: vector, keyword/BM25, graph, SQL, object store, live APIs. The agent picks the store per sub-question.
EmbeddingsSingle embedding model; query and docs share one space. Query = raw user text.Query rewrites, multi-vector (colbert-style) or late interaction when needed; optional embedding of plans (“search vendor graph” vs “search policy”). Can switch models per corpus.
RetrievalOne shot: embed → top-k → done. Fixed k, maybe a reranker.Iterative: retrieve → grade → rewrite → retrieve again. Hybrid (dense + sparse). Can expand (k up) or narrow (filters) based on grader scores.
ChunkingGlobal size/overlap at ingest. Chunks are the unit of truth forever.Ingest still chunks, but runtime can fetch parent docs, sections, tables, or whole files. Agent may re-chunk on the fly for a table or code symbol.
Indexing / freshnessBatch re-index; silent staleness.Agent can bypass the index (call source API), check updated_at, or trigger targeted re-embed. Conflicts become first-class signals.
Query understandingHope the embedding matches intent.Explicit intent, slots, and rewritten queries. Clarifying questions when slots are missing.
Reranking & gradingOptional cross-encoder on the same top-k.Document graders (relevant / irrelevant / insufficient) drive the loop. Separate answer faithfulness check after generation.
Context assemblyConcatenate top-k until token budget.Budget-aware packing: citations, diversity, recency, tenant ACL. Drop low-grade chunks; keep structured extracts.
Tools & actionsNone (or a single “search” behind the scenes).RAG is one tool among CRM, SQL, search, tickets, calculators. Plan → act → observe.
Failure behaviorGenerate anyway.Retry, switch retriever, ask user, or abstain with evidence of empty/conflicted context.
EvaluationSpot-check answers.Trace each retrieve/grade/tool; eval retrieval and agent trajectories, not only BLEU-like answer scores.
Access controlOften applied late (or not).Filter at retrieval time as part of the tool contract; agent never sees unauthorized chunks.
Cost & latencyPredictable: 1 embed + 1 LLM call.Variable: more hops. Production designs cap steps, cache rewrites, and use small models for graders.

Read the table as a migration map: you do not throw away your vector DB. You wrap it with a loop that can also leave the vector DB when the job demands it.

Main components of production-grade Agentic RAG

Think of Agentic RAG as a small operating system around retrieval, not as “RAG plus an agent prompt.”

┌──────────────────────────────────────────────────────────┐
│  Experience (chat, ticket, IDE, voice)                     │
└────────────────────────────┬─────────────────────────────┘
                             │
┌────────────────────────────▼─────────────────────────────┐
│  Orchestrator / planner  +  policy & step budget           │
└─┬──────────────┬──────────────┬──────────────┬───────────┘
  │              │              │              │
  ▼              ▼              ▼              ▼
 Query         Retriever      Tool           Memory
 understanding  tools         belt           (short + long)
 (rewrite,     (vector,       (SQL, CRM,     session,
  slots)        BM25, graph,   tickets,       episodic,
                parent-doc)    web, code)     tenant KB
  │              │              │              │
  └──────────────┴──────────────┴──────────────┘
                             │
              Graders + faithfulness + citations
                             │
              Generator (answer or action proposal)
                             │
              Tracing, eval, cache, human approval

1. Orchestrator (planner and state machine)

The orchestrator owns the run: goal, current plan, observations, remaining budget (max retrievals, max tokens, max seconds).

It should not be a free-form “do anything” agent in production. Prefer:

  • A state machine for known workflows (support, claims, KYC)
  • A planner that emits a short list of steps for open-ended research
  • Hard stop conditions: enough evidence, contradiction, user clarification needed, or budget exhausted

Store an explicit run object (run_id, goal, retrievals[], grades[], tool_traces[], status). That is what you debug when the answer is wrong.

2. Query understanding

Before any vector call:

  • Classify intent (definition, how-to, live status, comparison, action)
  • Extract slots (product, version, tenant, date range, entity ids)
  • Rewrite into one or more search queries (HyDE-style hypothetical docs are optional; often a crisp keyword + semantic pair works better)
  • Decide modality of search: semantic, keyword, id lookup, SQL, graph hop

This component is why Agentic RAG “simplifies” messy tickets: the first model call is cheap and shapes every later retrieve.

3. Retriever tools (not “the retriever”)

Expose retrieval as named tools with contracts:

  • semantic_search(corpus, query, filters, k)
  • keyword_search(...)
  • fetch_parent(chunk_id) / fetch_table(doc_id, table_id)
  • graph_neighbors(entity_id)
  • get_by_id(...) for canonical records

The agent (or the state machine) chooses. Simple RAG had one anonymous top-k. Production Agentic RAG has a tool registry so you can add a new corpus without rewriting the prompt from scratch.

4. Indexing, chunking, and document structure

Ingest is still critical:

  • Preserve hierarchy (doc → section → chunk) so the agent can expand
  • Special-case tables, code, and lists
  • Store metadata the agent will filter on: tenant, product, locale, effective_from, pii_class, owner
  • Keep sparse (BM25) alongside dense; hybrid is the default for proper nouns and error codes

Chunking is an index-time default plus a runtime expansion policy. That pairing is the practical fix for “RAG killed my table.”

5. Graders (the missing middle)

After retrieval, a small model or rules scores each chunk: relevant, partial, irrelevant, wrong version, unsafe.

Graders enable the rescue loop:

  • All irrelevant → rewrite query or switch tool
  • Partial → fetch_parent or increase k
  • Conflict → fetch metadata / system of record
  • Empty after N tries → abstain

Without graders, “agentic” is just extra latency.

6. Context packer and generator

Packing is a product decision: order by grade, cap tokens, keep citations, include why this chunk was chosen. The generator should be instructed to only use packed evidence for factual claims and to quote or cite when the domain requires it.

For actions, the generator produces a proposal (ticket body, SQL, patch) that policy may require a human to approve.

7. Memory

Three layers, or you will confuse them:

  • Working memory — this run’s observations and plan
  • Session memory — this user’s last clarifications and rejected paths
  • Long-term / tenant memory — approved facts, user preferences, prior resolutions (often another RAG corpus with stricter write rules)

Agentic RAG without memory re-asks and re-retrieves the same dead ends.

8. Policy, ACLs, and approvals

Every retriever tool applies tenant and role filters. The orchestrator must not “creatively” drop filters to “be helpful.” High-impact tools (email, production change, refund) sit behind allow-lists and confirmation.

This is the difference between a demo agent and something you can put in front of customers.

9. Observability and evaluation

Trace spans for rewrite, each retrieve, grades, tool calls, and final answer. Evaluate:

  • Retrieval: recall of gold passages, grade accuracy
  • Agent: did it take a useless hop? did it stop in time?
  • Answer: faithfulness to packed context, citation validity

Cache stable rewrites and hot retrievals so production cost does not look like an unbounded agent playground.

Mental models that make Agentic RAG easy

The librarian vs the researcher

Traditional RAG is a librarian: you ask once, they hand you three books, you write the essay. Agentic RAG is a researcher: they read a chapter, notice a citation, pull a database, discard a bad source, and only then write. Same library. Different job.

Retrieval is a sensor, not a brain

Embeddings sense “nearby meaning.” The orchestrator is the brain. If you keep stacking embedding tricks (new model, bigger k, magic chunk size) without a loop, you are polishing the sensor and hoping the brain appears.

Budget is a feature

Unlimited hops feel smart and bankrupt you. Production Agentic RAG is bounded agency: 3–8 steps, explicit caches, small graders, big LLM only for synthesis and hard planning. Constraint is what makes the design shippable.

Two quality gates beat one clever prompt

Gate 1: Is the evidence good enough? (graders)
Gate 2: Does the answer stick to the evidence? (faithfulness / citation check)

Naive RAG has neither. Most “the model hallucinated” bugs are gate failures, not model IQ.

A five-question checklist before you add an agent

  1. Is the failure multi-hop, stale, or tool-shaped — or just a bad index?
  2. Can a better filter + hybrid search + parent-doc fix it without an agent?
  3. If you need an agent, what is the max step count and abstain policy?
  4. Which tools are read-only retrieve vs side-effecting?
  5. Can you trace and eval a bad run in five minutes?

If you cannot answer (3)–(5), you do not have production Agentic RAG yet. You have a longer prompt.

A minimal production path

You do not need a swarm of agents on day one.

  1. Keep your vector + BM25 index and metadata filters.
  2. Add query rewrite and a relevance grader with one retry.
  3. Add parent-document fetch for weak chunks.
  4. Add one live tool (CRM, SQL, or tickets) behind an ACL.
  5. Add faithfulness and traces.
  6. Only then open the planner for open-ended research — with a step budget.

That sequence is how teams move from “RAG is not enough” to Agentic RAG that is enough for production, without boiling the ocean.

Closing

Simple RAG solved “the model has no documents.” It did not solve wrong neighbors, broken chunks, stale truth, multi-hop work, or actions. Agentic RAG solves those by making retrieval a repeatable, gradable, mixable tool inside a bounded orchestrator — with memory, policy, and traces as first-class parts of the design.

If you remember one line: production RAG is not a better index; it is a control loop that is allowed to retrieve again, fetch the source of truth, or refuse to answer.

Discussion

Loading comments…