A debugger for RAG applications: diagnoses retrieval, context, and grounding failures.
Project description
RAG Debugger
Your RAG chatbot is wrong.
But why?
RAG Debugger finds:
- bad retrieval
- irrelevant context
- hallucinated answers
- missing information
Install
pip install rag-debug-cli
Or from source, for development:
git clone https://github.com/Perevoznyi-Creation/rag_debugger.git
cd rag_debugger
pip install -e ".[dev]"
Usage
from rag_debugger import debug_rag
report = debug_rag(
question="What is the refund policy?",
retrieved_documents=[
"Customers can return products within 30 days.",
"Warranty lasts for 2 years.",
],
answer="Customers can return products within 30 days.",
)
print(report)
RAG Score: 85/100
Retrieval:
✓ (0.78) Customers can return products within 30 days.
✗ (0.31) Warranty lasts for 2 years.
Grounding:
✓ Answer supported by retrieved context
Problems:
⚠ Irrelevant document retrieved: Warranty lasts for 2 years.
Recommendation:
Reduce retrieval k from 2 to 1
CLI
rag-debug analyze examples/basic.json
rag-debug analyze examples/basic.json --html report.html
rag-debug evaluate examples/customer_questions.json
rag-debug evaluate examples/customer_questions.json --save before.json
rag-debug evaluate examples/customer_questions_v2.json --save after.json
rag-debug compare before.json after.json
Input JSON shape (single case):
{
"question": "How long are refunds?",
"documents": ["Refunds take 5 days"],
"answer": "Refunds take 30 days"
}
Dataset JSON shape (for evaluate, a list of cases, label optional):
[
{
"label": "refund timing",
"question": "How long are refunds?",
"documents": ["Refunds take 5 days"],
"answer": "Refunds take 30 days"
}
]
compare diffs two evaluate --save result files by matching case labels — useful for checking whether a RAG change (chunk size, top_k, prompt) actually helped:
Before: 38%
After: 53%
Change: +15%
Improvements:
warranty question (bad retrieval): 13 -> 72 (+59)
Choosing an LLM judge
Grounding/hallucination checks are done by an LLM judge, pluggable per provider. Set one API key and, optionally, pick the provider:
export GROQ_API_KEY="..." # free tier — default if RAG_DEBUGGER_JUDGE is unset
export OPENAI_API_KEY="..."
export ANTHROPIC_API_KEY="..."
export RAG_DEBUGGER_JUDGE="groq" # uses that provider's default model
export RAG_DEBUGGER_JUDGE="groq:<model-name>" # or pick a specific model
export RAG_DEBUGGER_JUDGE="openai:<model-name>"
export RAG_DEBUGGER_JUDGE="anthropic:<model-name>"
Each provider's default model is defined in src/rag_debugger/judges/<provider>_judge.py
(DEFAULT_MODEL) — check there or your provider's docs for current model names, since
they change over time and this README intentionally doesn't pin one.
Or override per call/command:
debug_rag(question=..., retrieved_documents=..., answer=..., judge="openai:<model-name>")
rag-debug analyze examples/basic.json --judge anthropic:<model-name>
OpenAI and Anthropic support are optional extras (pip install -e ".[openai]", ".[anthropic]", or ".[all-judges]" for both) — only the SDK for the provider you actually use needs to be installed.
For local development, put your key(s) in a .env.local file (gitignored) — both examples/basic.py and the CLI load it automatically.
LangChain integration
DebugRetriever wraps any existing BaseRetriever — it's a real Runnable, so it drops directly into an LCEL chain with no other changes:
from rag_debugger.integrations.langchain import DebugRetriever
retriever = DebugRetriever(retriever=my_vectorstore.as_retriever())
chain = retriever | prompt | llm
answer = chain.invoke("What is the refund policy?")
report = retriever.debug(answer)
print(report)
DebugRetriever remembers the query and documents from the most recent invoke(); .debug(answer) runs debug_rag() against them. Pass judge= the same way as debug_rag() (a spec string or Judge instance) if you don't want the RAG_DEBUGGER_JUDGE default. See examples/langchain_integration.py for a runnable end-to-end example.
Requires the langchain extra: pip install -e ".[langchain]".
LlamaIndex integration
Same pattern, for LlamaIndex's BaseRetriever:
from rag_debugger.integrations.llama_index import DebugRetriever
retriever = DebugRetriever(retriever=index.as_retriever())
nodes = retriever.retrieve("What is the refund policy?")
# ... build a response from `nodes` however your pipeline does ...
answer = "Customers can return products within 30 days."
report = retriever.debug(answer)
print(report)
DebugRetriever remembers the query and nodes from the most recent retrieve(); .debug(answer) runs debug_rag() against them (using each node's get_content()). It's a real BaseRetriever, so it's a drop-in replacement anywhere a LlamaIndex retriever is expected, including RetrieverQueryEngine. See examples/llama_index_integration.py for a runnable end-to-end example.
Requires the llama-index extra: pip install -e ".[llama-index]".
Logging
RAG Debugger uses the standard logging module (logger = logging.getLogger(__name__) per
module) and configures no handler of its own — as a library, it stays silent unless the
consuming application sets one up.
The CLI does configure a handler for you. Pass -v/--verbose (before the subcommand)
to see debug-level diagnostics — which judge/model was resolved, retrieval scoring
summaries, and per-case warnings during evaluate — on stderr:
rag-debug -v analyze examples/basic.json
Without -v, only warnings and errors are shown (e.g. a judge API call failing, or a
dataset case being skipped). Third-party libraries' own debug logs (httpx,
sentence-transformers, etc.) are not included even at -v, so this doesn't drown you
in noise.
Error handling
Every judge provider wraps its SDK's API errors (auth failures, rate limits, network
issues) into a RuntimeError with a clear message, instead of letting an SDK-specific
exception escape uncaught — the CLI's analyze/evaluate commands catch this and print
a clean Error: ... line rather than a raw traceback. evaluate_dataset() /
rag-debug evaluate treats a per-case runtime failure (e.g. one transient API error in
a 50-question dataset) as that one case being skipped, not the whole run failing —
DatasetEvaluation.failed lists which cases errored and why, and both the printed
summary and any --saved results reflect only the cases that actually completed.
A dataset file with a case missing a required field (question/documents/answer)
is a different kind of problem — a dataset-authoring mistake, not a runtime hiccup — and
still fails the whole run immediately with a clear error, on the reasoning that silently
skipping a malformed case could hide a bug in how the dataset was generated.
Known limitations
- Retrieval relevance uses raw cosine similarity from
all-MiniLM-L6-v2. Real-world scores for genuinely relevant pairs often land around 0.3-0.5, not near 1.0 — the default threshold is tuned for this, but may need adjusting for your domain. - The default Groq judge uses a free-tier model. Even at
temperature=0, Groq's batched serving does not guarantee identical output across calls, so on borderline paraphrase cases (e.g. "return" vs "refund") the verdict can occasionally flip between runs. Switching to a larger/stronger model on any provider (--judge openai:...or--judge anthropic:...) generally improves consistency.
Development
pip install -e ".[dev]"
python3 -m pytest tests/ -v # run the test suite (no API keys/network needed)
ruff check . # lint
ruff format . # format
See test_strategy.md for what the automated suite covers (and deliberately doesn't), and SELF_TEST.md for the manual checklist to run before publishing a new version.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rag_debug_cli-0.1.0.tar.gz.
File metadata
- Download URL: rag_debug_cli-0.1.0.tar.gz
- Upload date:
- Size: 29.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c13d85a781236a56c9187c38407907d95544e9c4bd5f95407cb1fb66cf1a5bcf
|
|
| MD5 |
638f645bc1a39e9d77307cb12c424f6a
|
|
| BLAKE2b-256 |
faf86acd9278bbca021864b171bffa73348f65588927fee7b9b3c3fd64bcd6d8
|
File details
Details for the file rag_debug_cli-0.1.0-py3-none-any.whl.
File metadata
- Download URL: rag_debug_cli-0.1.0-py3-none-any.whl
- Upload date:
- Size: 22.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c9c4ab89c5584f68628ac8e7a43366012f7d2e312bacdb11e2b0fd42822aa20a
|
|
| MD5 |
d160261d1c2b2c21416232ed4f64773b
|
|
| BLAKE2b-256 |
9873a0675d8e1b042c1f90fa68c05de1997a4ce42ce1d6e16041d5e8c88e4aff
|