Introduce huggingface dataset for sharing evaluation dbs

This commit is contained in:
Yiorgis Gozadinos 2026-01-26 15:53:37 +02:00
parent 50a1a6171c
commit 9b166969e2
No known key found for this signature in database
5 changed files with 149 additions and 3 deletions

View file

@ -1,6 +1,15 @@
# Changelog
## [Unreleased]
### Added
- **Evaluation Database Hosting**: Pre-built evaluation databases available on HuggingFace
- `evaluations download <dataset>` downloads pre-built databases from `ggozad/haiku-rag-eval-dbs`
- `evaluations upload <dataset>` uploads databases to HuggingFace (maintainer only)
- Supports `all` argument to download/upload all datasets at once
- Use `--force` flag to overwrite existing databases
- Avoids lengthy database rebuild times for users running benchmarks
### Changed
- **Dependencies**: Updated core dependencies

View file

@ -7,18 +7,48 @@ We evaluate `haiku.rag` on several datasets to measure both retrieval quality an
You can run evaluations with the `evaluations` CLI:
```bash
evaluations repliqa
evaluations wix
evaluations run repliqa
evaluations run wix
```
The evaluation flow is orchestrated with [`pydantic-evals`](https://github.com/pydantic/pydantic-ai/tree/main/libs/pydantic-evals), which we leverage for dataset management, scoring, and report generation.
### Pre-built Databases
Building evaluation databases from scratch can take a long time, especially for large datasets like OpenRAG Bench. Pre-built databases are available on HuggingFace:
```bash
# Download a specific dataset
evaluations download repliqa
# Download all datasets
evaluations download all
# Force re-download (overwrite existing)
evaluations download repliqa --force
```
Available datasets:
| Dataset | Size |
|---------|------|
| `repliqa` | ~18MB |
| `hotpotqa` | ~331MB |
| `wix` | ~511MB |
| `open_rag_bench` | ~14GB |
After downloading, run benchmarks with `--skip-db` to use the pre-built database:
```bash
evaluations run repliqa --skip-db
```
### Configuration
The benchmark script accepts several options:
```bash
evaluations repliqa --config /path/to/haiku.rag.yaml --db /path/to/custom.lancedb
evaluations run repliqa --config /path/to/haiku.rag.yaml --db /path/to/custom.lancedb
```
**Options:**

View file

@ -1,4 +1,7 @@
import asyncio
import shutil
import tempfile
import zipfile
from collections.abc import Mapping
from pathlib import Path
from typing import Any, cast
@ -6,6 +9,7 @@ from typing import Any, cast
import logfire
import typer
from dotenv import find_dotenv, load_dotenv
from huggingface_hub import HfApi, hf_hub_download
from pydantic_evals import Case, Dataset as EvalDataset
from pydantic_evals.evaluators import LLMJudge
from pydantic_evals.reporting import ReportCaseFailure
@ -24,6 +28,8 @@ from haiku.rag.utils import get_model
load_dotenv(find_dotenv(usecwd=True))
HF_REPO_ID = "ggozad/haiku-rag-eval-dbs"
logfire.configure(send_to_logfire="if-token-present", service_name="evals")
logfire.instrument_pydantic_ai()
configure_cli_logging()
@ -449,5 +455,103 @@ def run(
)
@app.command()
def download(
dataset: str = typer.Argument(..., help="Dataset key or 'all' to download all."),
force: bool = typer.Option(False, "--force", help="Overwrite existing database."),
) -> None:
"""Download pre-built evaluation database from HuggingFace."""
if dataset.lower() == "all":
specs = list(DATASETS.values())
else:
spec = DATASETS.get(dataset.lower())
if spec is None:
valid_datasets = ", ".join(sorted(DATASETS))
raise typer.BadParameter(
f"Unknown dataset '{dataset}'. Choose from: {valid_datasets}, all"
)
specs = [spec]
for spec in specs:
db = spec.db_path()
if db.exists() and not force:
console.print(
f"[yellow]Skipping {spec.key}: database already exists at {db}[/yellow]"
)
console.print("Use --force to overwrite.")
continue
console.print(f"[blue]Downloading {spec.key}...[/blue]")
zip_filename = f"{spec.db_filename}.zip"
try:
zip_path = hf_hub_download(
repo_id=HF_REPO_ID,
filename=zip_filename,
repo_type="dataset",
)
except Exception as e:
console.print(f"[red]Failed to download {spec.key}: {e}[/red]")
continue
# Remove existing database if force is set
if db.exists():
shutil.rmtree(db)
# Extract to the parent directory
db.parent.mkdir(parents=True, exist_ok=True)
with zipfile.ZipFile(zip_path, "r") as zf:
zf.extractall(db.parent)
console.print(f"[green]Downloaded {spec.key} to {db}[/green]")
@app.command()
def upload(
dataset: str = typer.Argument(..., help="Dataset key or 'all' to upload all."),
) -> None:
"""Upload evaluation database to HuggingFace (maintainer only)."""
if dataset.lower() == "all":
specs = list(DATASETS.values())
else:
spec = DATASETS.get(dataset.lower())
if spec is None:
valid_datasets = ", ".join(sorted(DATASETS))
raise typer.BadParameter(
f"Unknown dataset '{dataset}'. Choose from: {valid_datasets}, all"
)
specs = [spec]
api = HfApi()
for spec in specs:
db = spec.db_path()
if not db.exists():
console.print(f"[red]Database not found at {db}[/red]")
continue
console.print(f"[blue]Uploading {spec.key}...[/blue]")
zip_filename = f"{spec.db_filename}.zip"
with tempfile.TemporaryDirectory() as tmpdir:
zip_path = Path(tmpdir) / zip_filename
console.print("[dim]Creating zip archive...[/dim]")
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
for file in db.rglob("*"):
if file.is_file():
arcname = f"{spec.db_filename}/{file.relative_to(db)}"
zf.write(file, arcname)
console.print("[dim]Uploading to HuggingFace...[/dim]")
api.upload_file(
path_or_fileobj=str(zip_path),
path_in_repo=zip_filename,
repo_id=HF_REPO_ID,
repo_type="dataset",
)
console.print(f"[green]Uploaded {spec.key} to {HF_REPO_ID}[/green]")
if __name__ == "__main__":
app()

View file

@ -11,6 +11,7 @@ dependencies = [
"haiku.rag-slim",
"pydantic-ai-slim[evals,logfire]>=1.46.0",
"datasets>=4.5.0",
"huggingface_hub>=0.20.0",
"typer>=0.19.2,<0.20.0",
"python-dotenv>=1.2.1",
]

View file

@ -1345,6 +1345,7 @@ source = { editable = "evaluations" }
dependencies = [
{ name = "datasets" },
{ name = "haiku-rag-slim" },
{ name = "huggingface-hub" },
{ name = "pydantic-ai-slim", extra = ["evals", "logfire"] },
{ name = "python-dotenv" },
{ name = "typer" },
@ -1354,6 +1355,7 @@ dependencies = [
requires-dist = [
{ name = "datasets", specifier = ">=4.5.0" },
{ name = "haiku-rag-slim", editable = "haiku_rag_slim" },
{ name = "huggingface-hub", specifier = ">=0.20.0" },
{ name = "pydantic-ai-slim", extras = ["evals", "logfire"], specifier = ">=1.46.0" },
{ name = "python-dotenv", specifier = ">=1.2.1" },
{ name = "typer", specifier = ">=0.19.2,<0.20.0" },