GEPA uses evolutionary strategies to optimize prompts without gradient computation.
Quick Start (Minimal Config)
Only 6 fields required - everything else is auto-derived:
[prompt_learning]
algorithm = "gepa"
task_app_url = "https://st.usesynth.ai/s/rt_..." # from tunnel.url
total_seeds = 200
proposer_effort = "LOW"
proposer_output_tokens = "FAST"
num_generations = 10
children_per_generation = 5
# Optional: budget constraint (omit to use account balance)
max_cost_usd = 10.0
Run with:
import os
from synth_ai.sdk import PolicyOptimizationJob
def run_gepa():
job = PolicyOptimizationJob.from_config(
"my_config.toml",
api_key=os.environ["SYNTH_API_KEY"],
algorithm="gepa"
)
job.submit()
result = job.poll_until_complete()
print(f"Best score: {result.best_score}")
What Gets Auto-Derived?
When you use a minimal config, these fields are automatically calculated:
| Field | Default Logic |
|---|
train_seeds | 70% of total_seeds |
validation_seeds | 30% of total_seeds |
population.initial_size | max(10, min(30, n_train // 10)) |
population.crossover_rate | 0.5 |
mutation.rate | 0.3 |
archive.size | pop_size * 2 |
rollout.budget | 100,000,000 (effectively unlimited) |
rollout.max_concurrent | 20 |
Required Fields
| Field | Description |
|---|
task_app_url | URL of your task app (via SynthTunnel or Cloudflare tunnel) |
total_seeds | Total number of seeds in your dataset (auto-split 70/30) |
proposer_effort | "LOW_CONTEXT" | "LOW" | "MEDIUM" | "HIGH" - controls mutation model quality |
proposer_output_tokens | "RAPID" | "FAST" | "SLOW" - controls max output tokens |
num_generations | Number of evolutionary generations to run |
children_per_generation | Number of child candidates to generate per generation |
proposer_effort and proposer_output_tokens are required because they directly affect cost and quality tradeoffs. num_generations and children_per_generation are required because they determine the search budget.
Optional Budget Constraints
If you don’t specify any budget constraint, the job runs until your account balance is depleted.
# Choose one or more:
max_cost_usd = 10.0 # Stop when total spend reaches $10
max_rollouts = 5000 # Stop after 5000 rollouts
max_seconds = 3600 # Stop after 1 hour
Explicit Seed Specification
Instead of total_seeds, you can specify seeds explicitly:
[prompt_learning]
algorithm = "gepa"
task_app_url = "https://st.usesynth.ai/s/rt_..." # from tunnel.url
proposer_effort = "LOW"
proposer_output_tokens = "FAST"
train_seeds = { start = 0, end = 140 }
validation_seeds = { start = 140, end = 200 }
Overriding Defaults
Any auto-derived field can be overridden:
[prompt_learning]
algorithm = "gepa"
task_app_url = "https://st.usesynth.ai/s/rt_..." # from tunnel.url
total_seeds = 200
proposer_effort = "LOW"
proposer_output_tokens = "FAST"
# Override specific defaults
population_size = 30
num_generations = 15
Pinning Defaults Version
For reproducibility, you can pin the defaults version:
[prompt_learning]
defaults_version = "v1" # Locks behavior forever
# ... rest of config
If not specified, the latest version is used. When defaults change in future versions, your config will automatically get the new behavior unless you pin a version.
Full Config (Advanced)
For complete control, specify all fields explicitly:
[prompt_learning]
algorithm = "gepa"
task_app_url = "https://st.usesynth.ai/s/rt_..." # from tunnel.url
[prompt_learning.gepa]
env_name = "banking77"
proposer_effort = "LOW"
proposer_output_tokens = "FAST"
[prompt_learning.gepa.rollout]
budget = 100_000_000
max_concurrent = 20
[prompt_learning.gepa.evaluation]
train_seeds = { start = 0, end = 140 }
validation_seeds = { start = 140, end = 200 }
[prompt_learning.gepa.mutation]
rate = 0.3
[prompt_learning.gepa.population]
initial_size = 20
num_generations = 10
children_per_generation = 5
crossover_rate = 0.5
selection_pressure = 1.0
[prompt_learning.gepa.archive]
size = 64
pareto_set_size = 64
pareto_eps = 1e-6
feedback_fraction = 0.5
[prompt_learning.termination_config]
max_cost_usd = 10.0
max_trials = 1000
Tunnels
GEPA requires your task app to be accessible over HTTPS. Two tunnel backends are supported:
SynthTunnel (Recommended)
No external binary required. Supports 128 concurrent in-flight requests:
from synth_ai.core.tunnels import TunneledLocalAPI
tunnel = await TunneledLocalAPI.create(local_port=8001, api_key="sk_live_...")
job = PromptLearningJob.from_dict(
config,
task_app_url=tunnel.url,
task_app_worker_token=tunnel.worker_token,
)
[prompt_learning]
task_app_url = "https://st.usesynth.ai/s/rt_..." # from tunnel.url
Cloudflare
Requires cloudflared installed. Use task_app_api_key instead of worker_token:
from synth_ai.core.tunnels import TunneledLocalAPI, TunnelBackend
tunnel = await TunneledLocalAPI.create(
local_port=8001,
backend=TunnelBackend.CloudflareQuickTunnel,
)
[prompt_learning]
task_app_url = "https://random-words.trycloudflare.com"
See Tunnels for the full comparison.
See Also