rag-guard is a typed-decision layer for RAG. Before you see an answer, it checks that retrieval found something relevant, that there is enough of it, and that every claim is backed by the source.
The Transformer reached a BLEU score of 28.4 on the WMT 2014 English-to-German translation task.
Vector search finds passages that are close to a query in embedding space. That is not the same as passages that answer it, or an answer the passages actually support.
Retrieval misses the one chunk that answers the question, and nothing downstream knows to say so.
The context is too thin, but the model answers anyway: fluently, and wrong.
The answer reads fine, but you can't tell which parts the source text supports.
Each stage returns a probability you can threshold and log, not prose you have to parse. A "no" at any gate stops the pipeline before a guess is generated.
proceed / escalate / refuse
kept / dropped per chunk
clarify
insufficient_context
1 LLM call
ungrounded_answer_flagged
answered_with_caveat
There is no pre-built demo corpus, on purpose. Upload a .txt, .md or .pdf.
Chat normally. Every reply carries a visible reasoning trace.
Run one question through two embedding providers at once.
This app depends on rag-guard like any other project would, to prove the published package behaves as its docs and tests claim.
from rag_guard import RagGuard guard = RagGuard(model=decision_model) report = guard.run(query, chunks, generate_fn) assert report.action in ( "answered", "answered_with_caveat", "insufficient_context", "ungrounded_answer_flagged", "clarify", "escalate", "refuse", )
The judgment calls come from a pluggable decision model. Swap it without changing pipeline code:
Then open the trace and see exactly why it answered, or why it refused.
Open the app