Skip to main content
RAG failures split into two kinds - the retriever fetched the wrong chunks, or the generator ignored the right ones - and a single end-to-end score can’t tell you which. AgentX ships the standard component-split metrics as seeded evaluator configs (Evaluate → Evaluator), usable online (live traffic) and offline (dataset runs) with the same configs.

The metric pack

All five are ordinary evaluator configs: tune their criteria, reference them from online evaluators, or pass one as evaluation_settings_id on a run. Deleted ones stay deleted; new-in-a-release metrics seed once per instance.

Where the context comes from

{context} in these judge prompts resolves through the same precedence everywhere:
  1. Explicit - metadata.retrievalContext on a trace, or retrieval_context returned by your agent function in a run (string or list of chunk strings).
  2. Recorded retrievals - the trace’s own retrieval spans: tracer.trace_retrieval(...), LangChain/LlamaIndex retriever callbacks, OTel retrieval spans. No caller changes needed: if your integration already records retrievals, the judges see the chunks. Custom span names are fine (trace_retrieval("kb_search", ...)) - retrieval spans carry an explicit kind marker, so they’re recognized regardless of what you name them.
  3. Pinned (offline only) - the dataset case’s static retrievalContext.

Online: score live RAG traffic

Create an LLM judge scorer referencing a RAG config (Scorers → New scorer → LLM judge scorer, or the SDK) - every sampled trace is judged with whatever it actually retrieved:
A response claiming a 90-day refund while the retrieved policy chunk says 30 days scores 0, with the contradiction named in the justification - and raises a signal you can send straight to a regression dataset.

Offline: dataset runs with dynamic context

A real RAG agent retrieves per query, so return what it retrieved alongside the answer - the faithfulness judge grades against that run’s chunks, not a stale pin:
The explicit retrieval_context return is optional here - with the retrieval recorded on the linked trace, the engine pulls the chunks from its retrieval spans automatically; returning it just takes precedence. Contextual Recall additionally needs expected_results on the case (it attributes the reference answer’s claims to the context).

Deterministic: expected context match (no judge)

The five metrics above are LLM judges - each score is a model call. For retriever regression checks, a case can instead pin the chunks a correct retriever should fetch, and the engine compares them against what was actually retrieved with token-level Jaccard similarity - deterministic, free, and safe to run on every retriever, chunking, or embedding change:
The same field is editable in the dashboard: open a dataset case and fill Expected retrieval context (blank line between chunks), next to Expected tool calls. Full parameter reference: Build a dataset. Each result gets a Context match (jaccard) scorer row (0-1) next to any judge scores, computed from the same actual context the judges see (the result’s retrieval_context, else the linked trace’s retrieval spans). Jaccard measures token overlap, not meaning - use it to catch “the retriever stopped returning the right chunk”, and the judge metrics for whether the chunks are semantically right.

The loop

Capture retrievals → RAG pack scores live traffic → low scores raise signals → failing traces become dataset cases → offline runs guard the fix → CI gates keep it from regressing.

Runnable examples

Four end-to-end scripts in sample-scripts/sdk_rag_samples: online Faithfulness with automatic retrieval-span context, online Context Relevancy catching a broken retriever (and raising a high-severity signal), offline Faithfulness with dynamic per-case context, and the deterministic Jaccard retriever regression check.