Loading skill
Install any skill in seconds. Free to start, no credit card required.
Get Started Free →This skill helps an LLM generate correct AxGEPA optimization code using @ax-llm/ax. Use when the user asks about AxGEPA, GEPA, Pareto optimization, multi-objective prompt tuning, reflective prompt evolution, validationExamples, maxMetricCalls, or optimizing a generator, flow, or agent tree.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 25% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 50% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 39% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 117% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 162% | 0% |
Use this skill to generate GEPA optimization code. Prefer the top-level optimize(...) helper for normal code, and use direct AxGEPA / AxBootstrapFewShot only when the user needs low-level optimizer control.
optimize(program, train, metric, { studentAI, teacherAI, ... }) for normal generator and flow tuning.ai(), ax(), and flow() for new code.teacherAI and a cheaper studentAI.validationExamples when you have a holdout set.maxMetricCalls to bound optimizer cost; optimize(...) defaults it to 100.program.applyOptimization(result.optimizedProgram!).optimizedProgram.componentMap.axSerializeOptimizedProgram(...) and restore them with axDeserializeOptimizedProgram(...) so the same flow works in browsers and Node.optimize(...) runs AxBootstrapFewShot -> AxGEPA for small starter sets by default, preserving the demos in result.optimizedProgram.demos.optimize(...) and AxGEPA.compile() work for a single generator and for tree-aware roots such as flows or agents with registered optimizable descendants.AxGEPA for flows too.number or Record<string, number>.AxGen evaluator instead of writing a custom judge abstraction.maxMetricCalls must be large enough to cover the initial validation pass over validationExamples.getOptimizableComponents(). If a tree exposes no components, optimization will fail.validationExamples.result.optimizedProgram is the easy-to-apply best candidate. result.paretoFront is the full trade-off set for multi-objective runs.AxGEPA still has its own bootstrap option, but top-level optimize(...) composes the existing AxBootstrapFewShot optimizer before GEPA instead.Choose the evaluation path deliberately:
prediction and example.AxGen evaluator only when the task is genuinely qualitative and hard to score exactly.agent.optimize(...), prefer the built-in judge path instead of manually wrapping a judge metric. Normal agent users usually do not need to set target or metric at all.Rule of thumb:
optimize(...) on AxGen or flow: use a metric first, optionally a plain typed AxGen evaluator if needed.agent.optimize(...): use custom metric for crisp scoring, otherwise let the built-in judge handle scoring. Add judgeAI plus judgeOptions only when you want a stronger or separate judge model.typescriptimport { ai, ax, optimize, AxAIOpenAIModel } from '@ax-llm/ax'; const student = ai({ name: 'openai', apiKey: process.env.OPENAI_APIKEY!, config: { model: AxAIOpenAIModel.GPT54Mini }, }); const teacher = ai({ name: 'openai', apiKey: process.env.OPENAI_APIKEY!, config: { model: AxAIOpenAIModel.GPT54 }, }); const classifier = ax( 'emailText:string -> priority:class "high, normal, low", rationale:string' ); const train = [ { emailText: 'URGENT: Server down!', priority: 'high' }, { emailText: 'Weekly newsletter', priority: 'low' }, ]; const validation = [ { emailText: 'Invoice overdue', priority: 'high' }, { emailText: 'Lunch plans?', priority: 'low' }, ]; const metric = ({ prediction, example }: { prediction: any; example: any }) => prediction?.priority === example?.priority ? 1 : 0; const result = await optimize(classifier, train, metric, { studentAI: student, teacherAI: teacher, numTrials: 12, minibatch: true, minibatchSize: 4, earlyStoppingTrials: 4, sampleCount: 1, validationExamples: validation, maxMetricCalls: 120, }); classifier.applyOptimization(result.optimizedProgram!); console.log(result.bestScore);
typescriptimport { ai, flow, optimize, AxAIOpenAIModel } from '@ax-llm/ax'; const student = ai({ name: 'openai', apiKey: process.env.OPENAI_APIKEY!, config: { model: AxAIOpenAIModel.GPT54Mini }, }); const teacher = ai({ name: 'openai', apiKey: process.env.OPENAI_APIKEY!, config: { model: AxAIOpenAIModel.GPT54 }, }); const wf = flow<{ emailText: string }>() .n('classifier', 'emailText:string -> priority:class "high, normal, low"') .n( 'rationale', 'emailText:string, priority:string -> rationale:string "One concise sentence"' ) .e('classifier', (state) => ({ emailText: state.emailText })) .e('rationale', (state) => ({ emailText: state.emailText, priority: state.classifierResult.priority, })) .r((state) => ({ priority: state.classifierResult.priority, rationale: state.rationaleResult.rationale, })); const train = [ { emailText: 'URGENT: Server down!', priority: 'high' }, { emailText: 'Weekly newsletter', priority: 'low' }, ]; const validation = [ { emailText: 'Invoice overdue', priority: 'high' }, { emailText: 'Lunch plans?', priority: 'low' }, ]; const metric = ({ prediction, example }: { prediction: any; example: any }) => { const accuracy = prediction?.priority === example?.priority ? 1 : 0; const rationale = typeof prediction?.rationale === 'string' ? prediction.rationale : ''; const brevity = rationale.length <= 40 ? 1 : rationale.length <= 80 ? 0.5 : 0.1; return { accuracy, brevity }; }; const result = await optimize(wf, train, metric, { studentAI: student, teacherAI: teacher, numTrials: 16, minibatch: true, minibatchSize: 6, earlyStoppingTrials: 5, sampleCount: 1, validationExamples: validation, maxMetricCalls: 240, }); for (const point of result.paretoFront) { console.log(point.scores, point.configuration); } wf.applyOptimization(result.optimizedProgram!); console.log(result.optimizedProgram?.componentMap);
typescript// Scalar objective const scalarMetric = ({ prediction, example }) => prediction.answer === example.answer ? 1 : 0; // Multi-objective const multiMetric = ({ prediction, example }) => ({ accuracy: prediction.answer === example.answer ? 1 : 0, brevity: typeof prediction?.reasoning === 'string' && prediction.reasoning.length < 120 ? 1 : 0.2, });
0..1 so trade-offs are easy to reason about.typescriptconst { optimizedProgram, paretoFront } = result; program.applyOptimization(optimizedProgram!); // Save for later const saved = JSON.stringify(optimizedProgram); // Load later and re-apply const loaded = JSON.parse(saved); program.applyOptimization(loaded);
optimizedProgram.instruction and optimizedProgram.componentMap.componentMap, keyed by full component key.point.configuration.componentMap.typescriptconst optimizer = new AxGEPA({ studentAI, teacherAI, numTrials: 20, minibatch: true, minibatchSize: 5, minibatchFullEvalSteps: 5, earlyStoppingTrials: 5, minImprovementThreshold: 0, sampleCount: 1, seed: 42, verbose: true, });
numTrials: number of reflection/evolution rounds.minibatch: reduce per-round evaluation cost.minibatchSize: examples per minibatch.earlyStoppingTrials: stop after repeated non-improvement.minImprovementThreshold: reject tiny gains below this threshold.seed: stabilize sampling during demos and tests.train and validationExamples arrays.maxMetricCalls for at least one full validation pass plus several rounds.maxMetricCalls.auto: 'light' or fewer numTrials, then scale up.maxMetricCalls being too small: increase it until the initial validation pass fits.program.applyOptimization(...), not just setInstruction(...), so componentMap reaches the full tree.agent.optimize(...), set target: 'actor', 'responder', 'all', or explicit program IDs. The wrapper filters GEPA components to the selected target./Users/vr/src/ax/src/examples/optimize.ts/Users/vr/src/ax/src/examples/gepa.ts/Users/vr/src/ax/src/examples/gepa-flow.ts/Users/vr/src/ax/src/examples/gepa-train-inference.ts/Users/vr/src/ax/src/examples/gepa-quality-vs-speed-optimization.ts/Users/vr/src/ax/src/examples/axagent-gepa-optimization.tsOther measured skills in the registry, with their headline benchmark lift.