This benchmark evaluates Sonar's full RAG pipeline accuracy using the CRAG dataset, measuring how well the system retrieves relevant information and generates correct answers.
Demonstrate Sonar's RAG accuracy numerically through two complementary benchmarks:
- Benchmark A (Per-question): Small corpus (~50 pages per question), compares against CRAG paper baselines
- Benchmark B (Unified corpus): Large corpus (~60K pages shared across all questions), compares Sonar vs cloud RAG configuration
Key questions:
- Does Sonar's hybrid retrieval (BM25 + embedding + reranking) improve answer quality over naive approaches?
- How does a local LLM with good retrieval compare to cloud LLMs with simple retrieval?
- How does performance scale from small (50 pages) to large (60K pages) corpora?
CRAG (Comprehensive RAG Benchmark) provides:
- 4,409 Q&A pairs (2,706 in public split)
- 50 web pages pre-retrieved per question
- Ground truth answers with alternatives
- 5 domains: Finance, Sports, Music, Movie, Open
- Multiple question types: simple, multi-hop, comparison, aggregation, set, false_premise, post-processing
Reference: CRAG paper (arXiv:2406.04744)
Both benchmarks use CRAG's three-tier classification:
| Classification | Score | Criteria |
|---|---|---|
| Correct | +1 | Answer matches ground truth |
| Missing | 0 | Model declines to answer ("I don't know") |
| Incorrect | -1 | Wrong answer (hallucination) |
Aggregate metrics:
- Accuracy = correct / total
- Hallucination = incorrect / total
- Score = (correct - incorrect) / total = accuracy - hallucination
This penalizes hallucinations: a system that always says "I don't know" scores 0, while one that hallucinates gets negative scores.
Following the CRAG paper (Section 4.2), evaluation uses a two-step automatic approach:
-
Rule-based matching: If the generated answer exactly matches the ground truth (case-insensitive), classify as "correct". If the answer contains phrases like "I don't know" or "cannot answer", classify as "missing".
-
LLM-as-judge: For non-exact matches, an LLM classifies the answer into one of three categories: correct, incorrect, or missing.
The CRAG paper uses two LLM evaluators (gpt-3.5-turbo and
llama-3-70B-instruct) and reports the average to avoid self-preference bias.
This implementation uses gpt-4o-mini as a single evaluator for simplicity.
LLM-as-judge prompt:
Question: {question}
Ground truth: {expected}
Prediction: {generated}
Evaluate the prediction. Answer with just one word: correct, incorrect, or missing
(use "missing" if the prediction declines to answer or says "I don't know")
Each question searches within its own 50 pre-retrieved pages. This tests retrieval quality within a constrained set, matching the CRAG paper's Task 3 setup.
uv syncFirst, download the raw CRAG data:
cd rag-bench
uv run scripts/download_crag.pyThis downloads and extracts raw data to datasets/crag-raw/.
Then, process the raw data into the benchmark format:
uv run scripts/build_crag.pyOptions for build_crag.py:
--input-dir: Input directory for raw data (default:datasets/crag-raw)--output-dir: Output directory for processed data (default:datasets/crag)--sample-size N: Process only N samples (for testing)--seed N: Random seed for sampling (default: 42)
Output: datasets/crag/data.jsonl
Add the following to your Sonar settings (via Obsidian settings UI or
data.json):
{
"cragDataPath": "/absolute/path/to/rag-bench/datasets/crag/data.jsonl",
"cragOutputDir": "/absolute/path/to/rag-bench/runs",
"cragSampleSize": 100,
"cragOpenaiApiKey": "sk-..."
}Configuration options:
cragDataPath: Path to preprocessed CRAG datacragOutputDir: Directory for benchmark outputcragSampleSize: Number of samples to process (0 = all)cragSampleOffset: Number of samples to skip before processing (default: 0)cragOpenaiApiKey: OpenAI API key for LLM-as-judge evaluation (required)
Search parameters (chunking, reranking, result count, etc.) use Sonar's standard settings.
- Open Obsidian with Sonar enabled
- Wait for Sonar initialization (embedder + reranker ready)
- Open Command Palette (Cmd+P / Ctrl+P)
- Run Sonar: Run CRAG benchmark (end-to-end RAG)
The benchmark will:
- For each question, create a temporary IndexedDB
- Index the pages (chunking, embedding, BM25)
- Perform hybrid search with reranking
- Generate answer using the chat model
- Evaluate against ground truth
- Clean up temporary IndexedDB
Output files in runs/crag/:
results.jsonl: Per-question resultssummary.json: Aggregate metrics with domain/question_type breakdown
Configuration:
- Machine: MacBook Pro (Apple M2 Pro, 16-core GPU, 32 GB RAM)
- Embedding model:
BAAI/bge-m3- Reranker model:
BAAI/bge-reranker-v2-m3- Chat model:
Qwen/Qwen3-8B-GGUF- Samples: 100
| Metric | Value |
|---|---|
| Accuracy | 40.0% |
| Hallucination | 29.0% |
| Score | 11.0% |
Breakdown by domain and question type
Note: With only 100 samples, per-category results have high variance. Treat these as directional insights rather than statistically significant conclusions.
By domain:
| Domain | N | Accuracy | Hallucination | Score |
|---|---|---|---|---|
| open | 19 | 58% | 21% | 37% |
| music | 14 | 50% | 43% | 7% |
| movie | 15 | 40% | 13% | 27% |
| finance | 27 | 37% | 26% | 11% |
| sports | 25 | 24% | 40% | -16% |
By question type:
| Type | N | Accuracy | Hallucination | Score |
|---|---|---|---|---|
| simple | 27 | 63% | 19% | 44% |
| multi-hop | 6 | 50% | 50% | 0% |
| aggregation | 10 | 40% | 30% | 10% |
| set | 9 | 33% | 56% | -22% |
| post-processing | 6 | 33% | 50% | -17% |
| false_premise | 14 | 29% | 29% | 0% |
| simple_w_condition | 15 | 27% | 20% | 7% |
| comparison | 13 | 23% | 23% | 0% |
All baseline results are from CRAG paper (Table 5).
| Configuration | Accuracy | Hallucination | Score |
|---|---|---|---|
| GPT-4 Turbo (No RAG) | 33.5% | 13.5% | 20.0% |
| Llama 3 70B (No RAG) | 32.3% | 28.9% | 3.4% |
| GPT-4 Turbo + Naive RAG | 43.6% | 30.1% | 13.4% |
| Llama 3 70B + Naive RAG | 40.6% | 31.6% | 9.1% |
| Sonar Qwen 8B + RAG | 40.0% | 29.0% | 11.0% |
Notes:
- "No RAG" uses only the LLM's parametric knowledge without retrieved context
- "Naive RAG" concatenates search results in ranking order
- Sonar results use
gpt-4o-minias the single LLM evaluator, while the paper reports averages fromgpt-3.5-turboandllama-3-70B-instruct
- Small corpus per question: Each question only searches within 50 pre-retrieved pages, not a large corpus. This tests retrieval quality within a constrained set, not scalability.
- English-centric: CRAG is primarily English; results may not generalize to other languages.
All questions search within a single large corpus (~60K pages merged from all CRAG questions). This tests retrieval scalability and compares Sonar's local pipeline against a cloud RAG configuration.
| Aspect | Benchmark A (Per-question) | Benchmark B (Unified) |
|---|---|---|
| Corpus | ~50 pages per question | ~60K pages shared |
| Index | Created/destroyed per Q | Created once, shared |
| Search difficulty | 50 pages | 60K pages |
| Execution time | Slow (indexing per Q) | Fast (one-time indexing) |
| Comparison | vs CRAG paper baselines | Sonar vs Cloud RAG |
| Configuration | Embedding | Search | Generation |
|---|---|---|---|
| Sonar | BGE-M3 | Hybrid (BM25 + Vector) + Rerank | Qwen3-8B |
| Cloud (OpenAI) | text-embedding-3-large | Vector only (no reranking) | gpt-4.1-mini |
First, complete Benchmark A Steps 1-2 to download and process the CRAG dataset.
cd rag-bench
uv run scripts/build_crag_unified.py --sample-size 100Options:
--input: Input CRAG data file (default:datasets/crag/data.jsonl)--output-dir: Output directory (default:datasets/crag-unified)--sample-size N: Number of questions to sample (default: 100)--seed N: Random seed (default: 42)
Output:
datasets/crag-unified/corpus.jsonl: Unified corpus (deduplicated by URL)datasets/crag-unified/queries.jsonl: Sampled questionsdatasets/crag-unified/metadata.json: Statistics
Add the following to your Sonar settings:
{
"cragUnifiedCorpusPath": "/absolute/path/to/datasets/crag-unified/corpus.jsonl",
"cragUnifiedQueriesPath": "/absolute/path/to/datasets/crag-unified/queries.jsonl",
"cragUnifiedOutputDir": "/absolute/path/to/rag-bench/runs/crag-unified",
"cragUnifiedSampleSize": 0,
"cragUnifiedOpenaiApiKey": "sk-..."
}Configuration options:
cragUnifiedCorpusPath: Path to unified corpuscragUnifiedQueriesPath: Path to queries filecragUnifiedOutputDir: Directory for benchmark outputcragUnifiedSampleSize: Number of queries to evaluate (0 = all)cragUnifiedSampleOffset: Number of queries to skip (default: 0)cragUnifiedOpenaiApiKey: OpenAI API key (required for both evaluation and Cloud RAG)
- Open Obsidian with Sonar enabled
- Open Command Palette (Cmd+P / Ctrl+P)
- Run Sonar: Run CRAG Unified benchmark (Sonar vs Cloud)
The benchmark will:
-
Sonar evaluation:
- Index corpus with BGE-M3 embeddings + BM25
- For each query: hybrid search + reranking → Qwen3-8B generation
- Evaluate with LLM-as-judge
-
Cloud evaluation:
- Index corpus with OpenAI text-embedding-3-large (chunked for long docs)
- For each query: vector search only → gpt-4.1-mini generation
- Evaluate with LLM-as-judge
-
Generate comparison summary
Output files in runs/crag-unified/:
results-sonar.jsonl: Per-question Sonar resultsresults-cloud.jsonl: Per-question Cloud resultssummary-sonar.json: Sonar aggregate metricssummary-cloud.json: Cloud aggregate metricscomparison.json: Side-by-side comparison
Configuration:
- Machine: MacBook Pro (Apple M2 Pro, 16-core GPU, 32 GB RAM)
- Corpus: 4,652 documents (~60K pages deduplicated)
- Queries: 100 samples
Component Sonar Cloud (OpenAI) Embedding BGE-M3 text-embedding-3-large Retrieval BM25 + vector hybrid embedding similarity Reranking BGE-reranker-v2-m3 (none) Generation Qwen3-8B gpt-4.1-mini
| Metric | Sonar | Cloud (OpenAI) |
|---|---|---|
| Accuracy | 43% | 42% |
| Hallucination | 32% | 35% |
| Score | 11% | 7% |
| Indexing time | 6,245s | 1,133s |
| Query time | 33.5s/query | 1.7s/query |
| API cost | $0 | $2.66 |
-
Accuracy is comparable: Sonar achieves similar accuracy (43% vs 42%) to the cloud configuration despite using a local 8B parameter model vs GPT-4.1-mini.
-
Lower hallucination: Sonar has a 3% lower hallucination rate (32% vs 35%), resulting in a higher overall score (+4%).
-
Trade-off: speed vs cost: Cloud is ~20x faster per query (1.7s vs 33.5s) but costs $2.66/100 queries. Sonar is free but slower due to limited machine resources. Initial indexing is also slower (6,245s vs 1,133s), but this is a one-time cost.
Breakdown by domain and question type
Note: With only 100 samples, per-category results have high variance (some categories have as few as 3-15 samples). Treat these as directional insights rather than statistically significant conclusions.
By domain:
| Domain | N | Sonar | Cloud | Diff |
|---|---|---|---|---|
| open | 18 | 67% | 67% | 0% |
| sports | 15 | 60% | 47% | +13% |
| music | 15 | 53% | 60% | -7% |
| movie | 27 | 33% | 37% | -4% |
| finance | 25 | 20% | 16% | +4% |
By question type:
| Type | N | Sonar | Cloud | Diff |
|---|---|---|---|---|
| simple | 35 | 40% | 46% | -6% |
| multi-hop | 10 | 70% | 80% | -10% |
| simple_w_condition | 11 | 73% | 45% | +28% |
| set | 10 | 40% | 30% | +10% |
| comparison | 12 | 25% | 42% | -17% |
| false_premise | 12 | 25% | 25% | 0% |
| aggregation | 7 | 43% | 29% | +14% |
| post-processing | 3 | 33% | 0% | +33% |