GEPA: Genetic-Pareto optimizer for text-based system components.

Basic Example

trainset = [%{input: "What is 2+2?", answer: "4"}, ...]
valset = [%{input: "What is 5+5?", answer: "10"}]

{:ok, result} = GEPA.optimize(
  seed_candidate: %{"instruction" => "You are a helpful assistant."},
  trainset: trainset,
  valset: valset,
  adapter: GEPA.Adapters.Basic.new(),
  max_metric_calls: 100
)

IO.puts("Best score: #{GEPA.Result.best_score(result)}")
IO.inspect(GEPA.Result.best_candidate(result))

With LLM-based Reflection

llm = GEPA.LLM.req_llm(:openai, model: "gpt-5.4-mini")

{:ok, result} = GEPA.optimize(
  seed_candidate: %{"instruction" => "You are a helpful assistant."},
  trainset: trainset,
  valset: valset,
  adapter: GEPA.Adapters.Basic.new(),
  max_metric_calls: 100,
  reflection_llm: llm
)

This uses the LLM to propose improved instructions based on execution feedback, rather than using a simple placeholder improvement.

Summary

Functions

Build the official-style default adapter.

Run GEPA optimization.

Optimize an arbitrary candidate/evaluator pair.

Functions

default_adapter(opts)

@spec default_adapter(keyword()) :: GEPA.Adapters.Default.t()

Build the official-style default adapter.

This is a top-level convenience for callers coming from the upstream Python surface. It delegates to GEPA.Adapters.Default.new/1.

optimize(opts)

@spec optimize(Keyword.t()) :: {:ok, GEPA.Result.t()}

Run GEPA optimization.

Options

Required

  • :seed_candidate - Initial program as map of component -> text
  • :trainset - Training data (list or DataLoader)
  • :adapter - Adapter module/struct implementing GEPA.Adapter

If :adapter is omitted, provide :task_lm or :model and GEPA will build the default adapter. If :valset is omitted, GEPA reuses :trainset.

At least one stopping path is required: :max_metric_calls, :max_reflection_cost, :max_candidate_proposals, :stop_conditions, :stop_callbacks, or :run_dir (which adds a gepa.stop file stopper).

Optional

  • :valset - Validation data (list or DataLoader, default: :trainset)
  • :candidate_selection_strategy / :candidate_selector - :pareto, :current_best, :epsilon_greedy, :top_k_pareto, or a custom selector (default: :pareto)
  • :batch_sampler - Batch sampler or :epoch_shuffled (default: :epoch_shuffled)
  • :module_selector - :round_robin, :all, or a custom component selector (default: :round_robin)
  • :val_evaluation_policy - :full_eval or a custom evaluation policy (default: :full_eval)
  • :reflection_minibatch_size - Minibatch size (default: 3)
  • :perfect_score - Perfect score value (default: 1.0)
  • :skip_perfect_score - Skip if perfect (default: true)
  • :seed - Random seed (default: 0)
  • :run_dir - Directory for state persistence (default: nil)
  • :reflection_llm - LLM for generating improved instructions (default: nil)
  • :custom_candidate_proposer - Function used when no reflection LLM or adapter proposer is available
  • :proposal_template - Custom template for instruction proposal (default: built-in)
  • :structured_output - Use tool_use / function calling for instruction proposals (default: false)
  • :acceptance_criterion - Candidate acceptance criterion (default: :strict_improvement)
  • :cache_evaluation - Build an evaluation cache automatically (default: false)
  • :raise_on_exception - Propagate proposer/evaluator exceptions (default: true)
  • :use_merge - Enable merge proposer construction (default: false)
  • :max_merge_invocations - Maximum merge attempts when merge is enabled (default: 5)
  • :merge_val_overlap_floor - Minimum shared validation IDs for merge subsamples (default: 5)
  • :callbacks - Synchronous observational callbacks (default: [])
  • :track_best_outputs - Track best validation outputs in state/result (default: false)
  • :frontier_type - Pareto frontier mode: :instance, :objective, :hybrid, or :cartesian (default: :instance)
  • :progress - Enable progress display (default: false). Can be true or a keyword list with options: [width: 60, color: true]

Returns

{:ok, result} where result is a GEPA.Result struct

LLM-based Reflection

When :reflection_llm is provided, GEPA uses the LLM to propose improved instruction texts based on feedback from execution traces. This is the recommended mode for production use.

Without :reflection_llm, the adapter must implement propose_new_texts/4 or /3, or you must pass :custom_candidate_proposer. GEPA does not use a placeholder production mutation path.

Custom Templates

When using :reflection_llm, you can customize the prompt template with :proposal_template. The template must include these placeholders:

  • <curr_param> - Current instruction text
  • <side_info> - Formatted examples with feedback

Legacy {component_name}, {current_instruction}, and {reflective_dataset} templates are still accepted for existing Elixir callers.

Example:

custom_template = """
Improve this instruction:
Current: <curr_param>
Examples: <side_info>
New instruction:
"""

GEPA.optimize(..., reflection_llm: llm, proposal_template: custom_template)

optimize_anything(opts)

@spec optimize_anything(keyword() | map() | GEPA.OptimizeAnything.Config.t()) ::
  {:ok, GEPA.Result.t()} | {:error, term()}

Optimize an arbitrary candidate/evaluator pair.

This top-level entrypoint mirrors upstream gepa.optimize_anything while the implementation lives in GEPA.OptimizeAnything.optimize_anything/1.