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.
.claude/skills/ax-llm-ax-gepa/SKILL.md| 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.ts| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 14,362 | 5,720 | -60% | 1 | 1 | 0% | 3,244 | 4,060 | +25% | 0 | 0 | — |
case-02 | fail→pass | 14,717 | 8,978 | -39% | 1 | 1 | 0% | 3,310 | 4,953 | +50% | 0 | 0 | — |
case-03 | fail→pass | 14,857 | 8,736 | -41% | 1 | 1 | 0% | 3,402 | 4,735 | +39% | 0 | 0 | — |
case-04 | pass→pass | 8,759 | 7,573 | -14% | 1 | 1 | 0% | 1,691 | 4,222 | +150% | 0 | 0 | — |
case-05 | pass→pass | 10,098 | 5,281 | -48% | 1 | 1 | 0% | 1,849 | 3,806 | +106% | 0 | 0 | — |
case-06 | fail→pass | 10,999 | 9,506 | -14% | 1 | 1 | 0% | 2,185 | 4,744 | +117% | 0 | 0 | — |
case-07 | fail→pass | 6,632 | 3,247 | -51% | 1 | 1 | 0% | 1,293 | 3,389 | +162% | 0 | 0 | — |
case-08 | pass→pass | 6,526 | 3,944 | -40% | 1 | 1 | 0% | 1,220 | 3,543 | +190% | 0 | 0 | — |
case-09 | fail→pass | 8,914 | 4,541 | -49% | 1 | 1 | 0% | 1,696 | 3,696 | +118% | 0 | 0 | — |
case-10 | pass→pass | 11,768 | 6,542 | -44% | 1 | 1 | 0% | 2,251 | 4,106 | +82% | 0 | 0 | — |
case-11 | pass→pass | 10,898 | 8,352 | -23% | 1 | 1 | 0% | 1,873 | 4,377 | +134% | 0 | 0 | — |
case-12 | pass→pass | 5,920 | 1,810 | -69% | 1 | 1 | 0% | 910 | 3,052 | +235% | 0 | 0 | — |
case-13 | pass→pass | 11,250 | 7,684 | -32% | 1 | 1 | 0% | 2,321 | 4,352 | +88% | 0 | 0 | — |
case-14 | fail→pass | 6,770 | 3,003 | -56% | 1 | 1 | 0% | 1,304 | 3,189 | +145% | 0 | 0 | — |
case-15 | fail→pass | 10,990 | 4,582 | -58% | 1 | 1 | 0% | 2,051 | 3,626 | +77% | 0 | 0 | — |
case-16 | pass→pass | 11,210 | 9,670 | -14% | 1 | 1 | 0% | 2,158 | 4,671 | +116% | 0 | 0 | — |
case-17 | pass→pass | 14,615 | 6,991 | -52% | 1 | 1 | 0% | 2,561 | 3,920 | +53% | 0 | 0 | — |
case-18 | fail→pass | 10,265 | 7,002 | -32% | 1 | 1 | 0% | 1,803 | 4,113 | +128% | 0 | 0 | — |
case-19 | pass→pass | 11,418 | 7,423 | -35% | 1 | 1 | 0% | 2,389 | 4,196 | +76% | 0 | 0 | — |
case-20 | pass→pass | 11,125 | 7,762 | -30% | 1 | 1 | 0% | 2,537 | 4,461 | +76% | 0 | 0 | — |
case-21 | pass→pass | 16,369 | 12,220 | -25% | 1 | 1 | 0% | 3,316 | 5,505 | +66% | 0 | 0 | — |
case-22 | pass→pass | 8,628 | 7,615 | -12% | 1 | 1 | 0% | 1,878 | 4,463 | +138% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +41 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.