Monitoring a RAG Pipeline in Production
AUTHOR: Pramod Dutta
RAG monitoring is the discipline of tracking a retrieval-augmented generation pipeline's behavior after it ships, not just before. Most teams evaluate a RAG system once, ship it, and then only find out it's broken when a user complains that the chatbot made something up. By then the retriever might have been returning stale or empty chunks for weeks. This article covers what to instrument, how to structure the telemetry, and which failure modes actually show up once real traffic hits the system.
The core problem with RAG in production is that it has two independent failure surfaces: retrieval and generation. A generation-only eval (does the answer sound good?) tells you nothing about whether the retriever pulled the right documents. A retrieval-only eval (did we get relevant chunks?) tells you nothing about whether the model actually used them correctly. You need monitoring that separates these two concerns, because the fix for a retrieval failure (reindex, adjust chunking, fix embeddings) is completely different from the fix for a generation failure (adjust the prompt, change the model, add citation constraints).
Why RAG monitoring is different from standard APM
Standard application performance monitoring (APM) tracks latency, error rate, and throughput. Those still matter for RAG, but they miss the failure modes that are unique to retrieval-augmented systems:
- A request can return HTTP 200 with a fast response time and still be completely wrong, because the retriever pulled irrelevant chunks and the model hallucinated around them.
- The index can silently drift out of sync with the source of truth (a doc gets updated, the embedding doesn't), and nothing in your logs will flag it unless you specifically check for it.
- Embedding model or chunking changes upstream (a library update, a config change) can quietly degrade retrieval quality without touching a single error metric.
- Cost and latency both scale with the number of retrieved chunks and their token length, so a well-intentioned "just retrieve more context" change can double your spend without a corresponding quality gain.
This is why RAG monitoring needs its own metric taxonomy, not a repurposed web-service dashboard.
The three layers to instrument
Split your RAG pipeline into three observable layers: retrieval, generation, and the index/corpus itself. Each needs different metrics and different alerting thresholds.
Layer 1: Retrieval quality
This is the layer most teams under-instrument because it requires labels or a reference-free proxy metric, not just a pass/fail check. At minimum, log the following for every query:
- The raw query text (or a hash if you have privacy constraints) and any query rewriting/expansion applied to it.
- The retrieved chunk IDs, their similarity scores, and the rank order.
- The retrieval latency, broken out separately from generation latency.
- Which index or namespace was queried, if you run multiple collections.
On top of the raw logs, compute a rolling retrieval health signal. The two that are most practical to run continuously without human labeling are:
- Score distribution drift: track the mean and p50/p95 of top-k similarity scores over time. A sudden drop in scores across the board usually means either the query distribution shifted (new kind of user question) or the embeddings/index got corrupted.
- Empty or near-empty retrieval rate: the percentage of queries where the top result falls below your similarity threshold, or where fewer than k chunks are returned at all. This one metric alone catches a huge share of real production RAG failures, because it flags exactly the queries where the model has nothing to ground on and is most likely to hallucinate.
If you can afford it, run a small sample (1-5%) of production queries through an LLM-as-judge relevance check asynchronously, off the hot path. Ask the judge model a narrow question: "Given this query and these retrieved chunks, are the chunks relevant enough to answer the query? Yes/No/Partial." Aggregate this daily. Do not put judge calls in the request path, they add latency and cost for no user-facing benefit.
Layer 2: Generation quality
Generation metrics answer: given what the retriever handed the model, did the model produce a good, grounded answer?
- Faithfulness / groundedness: does the generated answer's factual content trace back to the retrieved chunks, or did the model add claims that aren't supported? This is the single most important RAG-specific metric because it's the direct proxy for hallucination. You can approximate it cheaply with an LLM judge that takes the answer and the retrieved chunks and outputs a supported/unsupported verdict per claim, or per sentence for shorter answers.
- Answer relevance: separate from faithfulness, does the answer actually address the question asked? A model can be perfectly faithful to the retrieved chunks while still dodging the user's actual question, usually because the retriever grabbed the wrong chunks in the first place.
- Citation accuracy: if your system shows sources, verify programmatically that the cited chunk IDs are actually in the retrieved set, and periodically spot-check that the cited chunk actually supports the sentence it's attached to. It is common for a system prompt to say "cite your sources" and for the model to cite the wrong document confidently.
- Refusal rate: track how often the model says some version of "I don't know" or declines to answer. Too low, and you likely have a hallucination problem where the model is answering when it shouldn't. Too high, and your retriever is probably starving the model of usable context on queries it should be able to answer.
- Token usage and cost per query: prompt tokens (context window) and completion tokens, tracked separately. A context window that creeps up over time, as chunking gets more generous or reranking passes more candidates through, is one of the most common silent cost leaks in a RAG system.
Layer 3: Index and corpus health
This layer is the one classic APM tools have zero visibility into, because the failure isn't in the request path at all.
- Freshness: for every source document, track the delta between "last updated at source" and "last reindexed." If your knowledge base pulls from a CMS, ticketing system, or docs repo, this delta should be a first-class metric with an alert threshold, not something you notice when a user reports outdated info.
- Index size and chunk count over time: sudden drops usually mean a failed reindex job silently truncated the collection. Sudden unexplained growth usually means a dedup step broke and you're inserting duplicate chunks, which quietly degrades retrieval by crowding out diverse results.
- Embedding model version: log which embedding model/version generated each vector. If you ever change embedding models without a full reindex, you end up with a corpus containing incompatible vector spaces, and similarity scores become meaningless for the mismatched subset. This is a surprisingly common production incident and it's invisible unless you tag vectors with their model version.
- Orphaned or dead-source chunks: chunks in the index whose source document has been deleted or is now access-restricted. These can leak stale or unauthorized content into answers if not cleaned up on a schedule.
Building the telemetry pipeline
You do not need a bespoke observability platform to start. The pattern that works well in practice:
- Structured logging at each pipeline stage. Emit one structured log event per stage (query received, retrieval completed, generation completed, response sent), each carrying a shared trace/request ID. This lets you reconstruct the full lifecycle of any single request later, which is essential when a user reports a bad answer and you need to see exactly what was retrieved.
{
"trace_id": "req_8f2a1c",
"stage": "retrieval",
"query": "how do I reset my api key",
"top_k": 5,
"chunk_ids": ["doc_44#3", "doc_12#1", "doc_44#4"],
"scores": [0.81, 0.77, 0.74],
"latency_ms": 142,
"index_version": "v14",
"embedding_model": "text-embedding-3-large"
}- Async evaluation jobs, not inline checks. Sample production traffic (start at 100% if volume is low, drop to a percentage once you have baseline data) and run faithfulness/relevance judging as a background job that reads from your log store, not as part of the live request. This keeps your evaluation logic decoupled from your latency budget and lets you iterate on judge prompts without redeploying the main service.
- A metrics store with time-series aggregation. Whether that's a hosted LLM observability tool, a general-purpose metrics stack like Prometheus plus Grafana, or a table in your existing data warehouse, the requirement is the same: you need to see trends over days and weeks, not just the last request. Retrieval score drift and freshness decay are only visible as trends.
- Alerting thresholds tied to business impact, not arbitrary percentages. "Alert if faithfulness drops below 90%" is meaningless without knowing your baseline. Run the pipeline for two to four weeks, establish your actual baseline distribution for each metric, then set alerts at something like 1.5-2 standard deviations below baseline, or at a hard floor you've decided is unacceptable regardless of history (for example, empty-retrieval rate above 5% is bad no matter what your historical average is).
A minimal monitoring setup you can build this week
If you're starting from zero, here's a pragmatic order of operations rather than trying to instrument everything at once:
- Day 1: add the trace-ID structured logging described above at every stage. This alone makes debugging individual bad answers dramatically faster, because you stop guessing what the retriever returned.
- Day 2: add the empty/near-empty retrieval rate metric and the score distribution tracking. This is the highest-signal, lowest-effort metric in the whole list.
- Day 3-4: stand up the async LLM-judge job for faithfulness on a small sample of traffic, logged against the trace ID so you can pull the full context when a low-faithfulness answer shows up.
- Day 5: add index freshness tracking tied to your source-of-truth update timestamps, and an alert if any document goes stale beyond your acceptable window (a day, a week, whatever your content update cadence is).
From there, layer in citation accuracy checks, refusal rate tracking, and cost-per-query dashboards as the system matures and you find out which failure modes actually recur for your specific corpus and user base.
Common production failure patterns to watch for
A few patterns show up repeatedly across RAG deployments, and each maps directly to one of the metrics above:
- The "confidently wrong" pattern: retrieval scores look fine, latency is fine, but faithfulness silently drops. Usually caused by a prompt change that loosened grounding instructions, or a model upgrade that changed how aggressively the model extrapolates beyond its context.
- The "stale index" pattern: everything about the pipeline is healthy except the underlying documents are out of date. This shows up as users getting outdated but plausible-sounding answers, which is worse than an obvious error because nobody reports it as a bug.
- The "context dilution" pattern: someone increases top-k or adds a reranking pass "to be safe," and average faithfulness drops because the model now has more low-relevance chunks competing for attention in the prompt. Watch token usage and faithfulness together whenever retrieval parameters change.
- The "silent reindex failure" pattern: a scheduled reindex job errors out partway through, but because it's a background job with no monitoring, nobody notices until index size or freshness metrics are checked, or a user notices missing content.
Each of these is invisible to a standard uptime/latency dashboard and each is directly caught by one of the retrieval, generation, or index metrics described above.
FAQ
What's the single most important metric to track first? Empty or near-empty retrieval rate. It requires no labeling, no LLM judge calls, and directly flags the queries most likely to produce hallucinated answers, because the model has nothing solid to ground on.
Do I need a dedicated LLM observability platform, or can I build this myself? You can build a functional version with structured logs, a background evaluation job, and a time-series dashboard on infrastructure you likely already run. Dedicated platforms save setup time and often ship pre-built RAG-specific dashboards, but the underlying signals (retrieval scores, faithfulness, freshness) are the same regardless of tooling.
How often should I run faithfulness evaluation on production traffic? Continuously on a sample, not on every request. Running an LLM judge inline on 100% of traffic adds latency and cost with no user benefit. A 1-10% background sample, aggregated daily, is enough to catch drift early in most deployments.
What's a reasonable empty-retrieval rate to target? There's no universal number, it depends on your corpus coverage and how open-ended your users' queries are. What matters more than the absolute number is the trend: establish your baseline in the first few weeks, then alert on meaningful deviation from that baseline rather than chasing an arbitrary target.
Should retrieval and generation failures trigger the same alert? No. Route them separately. A retrieval alert usually means an indexing, chunking, or embedding problem and gets routed to whoever owns the data pipeline. A generation alert usually means a prompt, model, or context-window problem and gets routed to whoever owns the LLM integration. Merging them into one generic "RAG is degraded" alert slows down diagnosis because the on-call engineer has to re-derive which layer actually failed.
How do I monitor RAG cost without a dedicated billing dashboard? Log prompt tokens and completion tokens per request as part of your structured logging, tagged with the model used. Aggregate by day and watch the prompt-token trend specifically, since that's the number that creeps up silently as retrieval parameters change, while completion tokens usually stay stable for a given task.
Can I reuse my existing APM tool for this, or do I need something RAG-specific? Your APM tool is still correct for latency, error rate, and infrastructure health, keep using it for those. But it has no concept of retrieval relevance, faithfulness, or index freshness, so you'll need to add those as custom metrics either in the same tool (if it supports custom time series) or in a separate lightweight system alongside it. Think of it as an additional layer, not a replacement.
BootcampA 30-day guided bootcamp: build, harden and ship a production autonomous agent from scratch.
AI AgentsUnderstand how AI agents really work: the loop, the tools, the memory, and why most agent projects fail.
Related reading