Skip to main content
Now that the hybrid RAG pipeline (BM25 + vector store + LLM) is running, this guide shows how to test it, inspect retrieved sources, and tune the main knobs (chunking, retrieval budget, reranking) to improve accuracy and reduce hallucination.
The image contains the text "Testing your RAG System" and "Demo" with a modern design layout. It also includes a copyright notice for KodeKloud.
Overview
  • Run queries against the hybrid retriever (BM25 + vector store) and inspect which document chunks are returned as sources.
  • Tune chunking parameters (size / overlap), per-retriever candidate counts (k_each), and final_k (how many merged candidates are passed to the LLM).
  • Check for hallucinations by asking questions that cannot be answered from your corpus.
  • Iterate: change one parameter at a time and re-run a fixed set of test queries to measure the effect.
Key helper functions (core snippets) The following core functions are typical building blocks for a small hybrid RAG prototype:
  • read_text_files: read .txt documents into a dict mapping filenames to text.
  • chunk_text: split large documents into overlapping chunks to maintain context during retrieval.
  • tokenize: simple tokenizer useful for building BM25 indices.
  • rrf_merge: Reciprocal Rank Fusion to merge ranked results from multiple retrievers.
Example implementation:
CLI arguments (parser snippet)
  • k_each: how many candidates to fetch from each retriever (BM25, vector).
  • final_k: how many merged, deduplicated candidates to include in the LLM prompt.
First queries and expected behavior
  • Example corpus for these tests: two books — Adventures of Sherlock Holmes and Frankenstein.
  • Test question: “Who is the narrator of this document?”
Run:
Typical returned answer (example):
Notes:
  • If retrieval returns chunks from multiple books, that is expected for a mixed corpus. To isolate testing to a single book, reset the index and re-ingest only that book.
Resetting and re-ingesting If you need to reset the vector index (for example ChromaDB), remove or reset the vector store directory and re-run ingestion to build a deterministic test set.
Be careful when removing your vector store directory (e.g., rm -rf .chroma) — this will delete the indexed embeddings and cannot be undone unless you have a backup.
Example commands:
After ingesting only Sherlock Holmes, re-run the same query and the system should be more consistent identifying Dr. Watson as the narrator. Tuning knobs and examples Use the following parameters to tune retrieval accuracy and LLM input quality.
  1. Chunk size and overlap
    • Larger chunk size and more overlap preserve more contiguous context, improving answers for questions that require extended context (addresses, sequences, long descriptions).
    • Example change: set defaults to chunk_size=1024 and overlap=200, then re-ingest.
  1. k_each and final_k (retrieval budget)
    • k_each: how many candidates to pull from each retriever (per-retriever).
    • final_k: number of merged candidates passed to the LLM after dedupe and rerank.
    • Example usage:
Observations and examples
  • Query phrasing matters. Some phrasings produce concise, accurate answers; others need more context from retrieval.
    • Example: “Who lives on Baker Street?” often returns: “Sherlock Holmes lives on Baker Street, at 221B.”
    • However, “What is Holmes’ address?” may produce “I don’t know.” if the retrieved chunks lack the exact address context.
  • Keyword searches can be very effective: searching for “221B” or “Irene Adler” often returns precise chunks.
Example:
Testing for hallucination
  • Intentionally ask questions that are not covered by the corpus to verify the system returns “I don’t know” (or a safe decline) instead of inventing facts.
  • Example queries:
    • “What is Holmes’ mother’s maiden name?”
    • “Which smartphone did Holmes prefer?”
Best practices:
  • Ensure your prompt explicitly instructs the LLM: “Do not make assumptions. If the answer is not supported by the provided sources, respond: ‘I don’t know.’”
  • When the system hallucinates, revisit:
    • Retrieval quality (chunking and overlap)
    • Score thresholds and reranking logic
    • Prompt engineering (explicit refusal instructions)
    • Increasing final_k (balance against token budgets)
Example:
Testing strategies and checklist
  • Sanity checks: ask questions with known answers from the corpus.
  • Hallucination checks: ask questions that are outside the corpus.
  • Rephrase checks: ask the same question with different phrasing to test semantic search robustness.
  • Isolate tests: re-ingest a single document for deterministic behavior.
  • Systematic tuning: change one parameter at a time (chunk size, then k_each, then final_k) and record results.
  • Track compute: increasing k_each and final_k raises recall but also uses more compute and tokens.
Practical tip
When tuning, change one parameter at a time (e.g., chunk size, then k_each, then final_k) and re-run a fixed set of test queries so you can measure the effect of each change.
Summary
  • Testing a RAG system is iterative: tune chunking, retrieval budgets, and reranking while validating results with curated test queries.
  • Use deterministic checks (keyword-based queries) plus open-ended checks (possible hallucination prompts).
  • Add clear refusal instructions in your prompt so the LLM avoids unsupported inferences.
  • Maintain a fixed suite of positive and negative test queries to measure improvement over time.
Further reading and references Thanks for following this lesson. Use the accompanying code and sample data to experiment and share results with the KodeKloud community.

Watch Video