Chaining optimizers

Some projects benefit from running two or more optimizers back-to-back. For example, use MetaPrompt to improve wording, then Parameter optimizer to fine-tune sampling settings. This guide explains why you might chain runs, the trade-offs, and the APIs you use to pass prompts and metadata between stages.

Strategy patterns

PipelineWhy run itProsConsComplexity
Hierarchical Reflective → ParameterExisting long/complex prompt scenario: Reflective analysis finds failure modes; Parameter optimizer then tightens parameters on the improved prompt.Excellent for legacy prompts with lots of existing complexity. Helps produce explainable changelog.Requires metrics with rich reason strings; two stages increase cost.Medium
Evolutionary → Few-Shot BayesianCold-start scenario: explore many prompt architectures first, then let Few-Shot Bayesian pick the best example combination for the winning structure.High diversity followed by precise example selection.Evolutionary runs are expensive; Bayesian stage relies on curated datasets.High
MetaPrompt → ParameterBaseline prompts need polish plus sampling tweaks.Quick wins with minimal configuration; can run in under an hour.Less insight into failure modes than reflective pipelines.Low.
Evolutionary → ParameterHunt for novel prompts, then squeeze out cost/latency by tuning temperature/top_p.Balances creativity with production readiness.Two heavy optimization loops; ensure budget headroom.High.

Example pipeline

1from opik_optimizer import MetaPromptOptimizer, ParameterOptimizer, ChatPrompt
2from opik_optimizer.parameter_optimizer import ParameterSearchSpace
3
4meta = MetaPromptOptimizer(model="openai/gpt-4o")
5parameter = ParameterOptimizer(model="openai/gpt-4o")
6
7meta_result = meta.optimize_prompt(
8 prompt=prompt,
9 dataset=dataset,
10 metric=metric,
11 max_trials=4,
12)
13
14# Reuse the optimized prompt from the first stage
15optimized_prompt = prompt.with_messages(meta_result.prompt)
16
17search_space = ParameterSearchSpace(parameters=[
18 {"name": "temperature", "distribution": "float", "low": 0.1, "high": 0.9},
19 {"name": "top_p", "distribution": "float", "low": 0.7, "high": 1.0},
20])
21
22final_result = parameter.optimize_parameter(
23 prompt=optimized_prompt,
24 dataset=dataset,
25 metric=metric,
26 parameter_space=search_space,
27 max_trials=20,
28)

Checklist

  • Freeze datasets and metrics between stages to keep comparisons fair.
  • Log pipeline metadata (e.g., experiment_config={"pipeline": "hierarchical_then_param"}) so dashboards show lineage.
  • Budget tokens – chained runs multiply costs; start with smaller n_samples and increase once results look promising.
  • Reuse OptimizationResult – every optimizer returns an OptimizationResult, so you can pass result.prompt (and result.details, result.history) directly into the next stage without rebuilding state.

Automation tips

  • Use Makefiles or CI workflows to run stage 1 → stage 2 with clear checkpoints.
  • Store intermediate prompts in version control alongside metadata (optimizer, score, dataset).
  • Notify stakeholders with summary reports generated from final_result.history.