Rename iterations to num_candidates

This commit is contained in:
Yiorgis Gozadinos 2026-03-12 13:00:51 +02:00
parent 5b3ad9bae7
commit 6ac5f277d8
No known key found for this signature in database
6 changed files with 18 additions and 21 deletions

View file

@ -3,14 +3,10 @@
### Added ### Added
- **GEPA prompt optimization**: `evaluations optimize` command for automated QA system prompt improvement using evolutionary optimization with LLM-judged scoring - **GEPA prompt optimization**: `evaluations optimize` command for automated QA system prompt improvement using evolutionary optimization with LLM-judged scoring. Cases are split 50/50 into train/val sets; GEPA budget is auto-computed from `--num-candidates` and dataset size.
- **Tuning docs**: Added step 7 (Optimize QA Prompts) to the tuning workflow in `docs/tuning.md` - **Tuning docs**: Added step 7 (Optimize QA Prompts) to the tuning workflow in `docs/tuning.md`
- **Evaluations test coverage**: Tests for evaluators (MAP, MRR), config, benchmark helpers, dataset mappers/builders, and optimization - **Evaluations test coverage**: Tests for evaluators (MAP, MRR), config, benchmark helpers, dataset mappers/builders, and optimization
### Changed
- **Optimization train/val split**: Cases are now split 50/50 into train and val sets. GEPA budget is auto-computed from `--iterations` and dataset size, replacing the broken `--max-calls` parameter that counted per-example evaluations
### Fixed ### Fixed
- **Read-only mode table creation**: `--read-only` no longer creates lance tables when pointed at an empty directory. `Store._init_tables()` now raises `ReadOnlyError` when tables are missing in read-only mode. - **Read-only mode table creation**: `--read-only` no longer creates lance tables when pointed at an empty directory. `Store._init_tables()` now raises `ReadOnlyError` when tables are missing in read-only mode.

View file

@ -76,7 +76,7 @@ The `evaluations optimize` command uses GEPA (Generalized Evolutionary Prompt Al
evaluations optimize wix evaluations optimize wix
# Constrained run # Constrained run
evaluations optimize repliqa --limit 40 --iterations 30 evaluations optimize repliqa --limit 40 --num-candidates 30
# Save result # Save result
evaluations optimize wix --output optimized_prompt.txt evaluations optimize wix --output optimized_prompt.txt
@ -85,7 +85,7 @@ evaluations optimize wix --output optimized_prompt.txt
| Option | Default | Description | | Option | Default | Description |
|--------|---------|-------------| |--------|---------|-------------|
| `--limit` | all cases | QA cases to use (split 50/50 train/val) | | `--limit` | all cases | QA cases to use (split 50/50 train/val) |
| `--iterations` | `50` | Optimization iterations | | `--num-candidates` | `50` | Number of candidate prompts to evaluate |
| `--output` | — | Save optimized prompt to file | | `--output` | — | Save optimized prompt to file |
| `--config` | auto | haiku.rag YAML config path | | `--config` | auto | haiku.rag YAML config path |
| `--db` | auto | Database path override | | `--db` | auto | Database path override |

View file

@ -62,7 +62,7 @@ Optimize QA system prompts using GEPA (Generalized Evolutionary Prompt Algorithm
```bash ```bash
evaluations optimize wix evaluations optimize wix
evaluations optimize repliqa --limit 40 --iterations 30 evaluations optimize repliqa --limit 40 --num-candidates 30
evaluations optimize wix --output optimized_prompt.txt evaluations optimize wix --output optimized_prompt.txt
``` ```

View file

@ -483,8 +483,8 @@ def optimize(
limit: int | None = typer.Option( limit: int | None = typer.Option(
None, "--limit", help="Limit QA cases (split 50/50 into train/val)." None, "--limit", help="Limit QA cases (split 50/50 into train/val)."
), ),
iterations: int = typer.Option( num_candidates: int = typer.Option(
50, "--iterations", help="Number of optimization iterations." 50, "--num-candidates", help="Number of candidate prompts to evaluate."
), ),
output: Path | None = typer.Option( output: Path | None = typer.Option(
None, "--output", help="Save optimized prompt to file." None, "--output", help="Save optimized prompt to file."
@ -509,7 +509,7 @@ def optimize(
spec=spec, spec=spec,
config=app_config, config=app_config,
cases=cases, cases=cases,
iterations=iterations, num_candidates=num_candidates,
db_path=db, db_path=db,
output=output, output=output,
) )

View file

@ -205,6 +205,7 @@ class ReflectionLM:
return result.output return result.output
# Cases per GEPA reflection minibatch (used for budget calculation)
REFLECTION_MINIBATCH_SIZE = 3 REFLECTION_MINIBATCH_SIZE = 3
@ -212,7 +213,7 @@ def run_optimization(
spec: DatasetSpec, spec: DatasetSpec,
config: AppConfig, config: AppConfig,
cases: list[QACase], cases: list[QACase],
iterations: int, num_candidates: int,
db_path: Path | None = None, db_path: Path | None = None,
output: Path | None = None, output: Path | None = None,
) -> dict[str, Any]: ) -> dict[str, Any]:
@ -239,16 +240,16 @@ def run_optimization(
trainset = cases[:mid] trainset = cases[:mid]
valset = cases[mid:] valset = cases[mid:]
# Budget: initial valset eval + worst-case iterations # Budget: initial valset eval + per-candidate worst case
# (each iteration: 2 minibatch evals + full valset if accepted) # (each candidate: 2 minibatch evals + full valset if accepted)
max_metric_calls = len(valset) + iterations * ( max_metric_calls = len(valset) + num_candidates * (
2 * REFLECTION_MINIBATCH_SIZE + len(valset) 2 * REFLECTION_MINIBATCH_SIZE + len(valset)
) )
console.print(f"Optimizing prompt for dataset: {spec.key}", style="bold magenta") console.print(f"Optimizing prompt for dataset: {spec.key}", style="bold magenta")
console.print( console.print(
f"Train: {len(trainset)}, Val: {len(valset)}, " f"Train: {len(trainset)}, Val: {len(valset)}, "
f"Iterations: {iterations}, GEPA budget: {max_metric_calls}" f"Candidates: {num_candidates}, Budget: {max_metric_calls} eval calls"
) )
console.print(f"Seed prompt length: {len(seed_prompt)} chars") console.print(f"Seed prompt length: {len(seed_prompt)} chars")

View file

@ -307,7 +307,7 @@ class TestRunOptimization:
spec=spec, spec=spec,
config=AppConfig(), config=AppConfig(),
cases=cases, cases=cases,
iterations=10, num_candidates=10,
db_path=tmp_path / "test.lancedb", db_path=tmp_path / "test.lancedb",
) )
@ -337,7 +337,7 @@ class TestRunOptimization:
spec=spec, spec=spec,
config=AppConfig(), config=AppConfig(),
cases=cases, cases=cases,
iterations=5, num_candidates=5,
db_path=tmp_path / "test.lancedb", db_path=tmp_path / "test.lancedb",
output=output_path, output=output_path,
) )
@ -371,7 +371,7 @@ class TestRunOptimization:
spec=spec, spec=spec,
config=AppConfig(), config=AppConfig(),
cases=cases, cases=cases,
iterations=1, num_candidates=1,
db_path=tmp_path / "test.lancedb", db_path=tmp_path / "test.lancedb",
) )
@ -404,12 +404,12 @@ class TestRunOptimization:
spec=spec, spec=spec,
config=AppConfig(), config=AppConfig(),
cases=cases, cases=cases,
iterations=5, num_candidates=5,
db_path=tmp_path / "test.lancedb", db_path=tmp_path / "test.lancedb",
) )
call_kwargs = mock_gepa.call_args[1] call_kwargs = mock_gepa.call_args[1]
assert len(call_kwargs["trainset"]) == 5 assert len(call_kwargs["trainset"]) == 5
assert len(call_kwargs["valset"]) == 5 assert len(call_kwargs["valset"]) == 5
# Budget = valset_size + iterations * (2*minibatch + valset_size) # Budget = valset_size + num_candidates * (2*minibatch + valset_size)
assert call_kwargs["max_metric_calls"] == 5 + 5 * (2 * 3 + 5) assert call_kwargs["max_metric_calls"] == 5 + 5 * (2 * 3 + 5)