Documentation

Build LLM-powered agents
with production-ready TypeScript

DSPy for TypeScript. Working with LLMs is complex—they don't always do what you want. DSPy makes it easier to build amazing things with LLMs. Just define your inputs and outputs (signature) and an efficient prompt is auto-generated and used. Connect together various signatures to build complex systems and workflows using LLMs.

15+ LLM Providers
End-to-end Streaming
Auto Prompt Tuning

Optimization Guide

Ax optimization now centers on two ideas:

For agents, the easiest entry point is usually agent.optimize(...), which defaults to actor optimization and uses the built-in LLM judge when you do not provide a custom metric.

Start with agent.optimize(...)

Most agent users can begin with a small task set:

const tasks = [
  {
    input: { query: 'Help Acme with the current checkout incident.' },
    criteria:
      'Look up the account, inspect the incident, and return the current workaround with urgent priority.',
    expectedActions: ['support.lookupAccount', 'support.lookupIncident'],
  },
];

const result = await assistant.optimize(tasks, {
  bootstrap: true,
});

assistant.applyOptimization(result.optimizedProgram!);

What Ax does by default:

Save and Load Optimized Artifacts

Artifacts are plain JSON-safe values, so you can store them in files, a database, localStorage, or IndexedDB:

import {
  axDeserializeOptimizedProgram,
  axSerializeOptimizedProgram,
} from '@ax-llm/ax';

const saved = axSerializeOptimizedProgram(result.optimizedProgram!);
const restored = axDeserializeOptimizedProgram(saved);

assistant.applyOptimization(restored);

V1 persists the selected demos and optimized component values. Raw failed traces and reflective datasets stay runtime-only.

AxBootstrapFewShot

Use bootstrap few-shot when you want a quick improvement from a small example set.

import { AxBootstrapFewShot, ai, ax } from '@ax-llm/ax';

const llm = ai({
  name: 'openai',
  apiKey: process.env.OPENAI_APIKEY!,
});

const classifier = ax(
  'review:string -> sentiment:class "positive, negative, neutral"'
);

const examples = [
  { review: 'I love this.', sentiment: 'positive' },
  { review: 'This is awful.', sentiment: 'negative' },
  { review: 'It is okay.', sentiment: 'neutral' },
];

const metric = ({ prediction, example }) =>
  prediction.sentiment === example.sentiment ? 1 : 0;

const optimizer = new AxBootstrapFewShot({
  studentAI: llm,
  examples,
});

const result = await optimizer.compile(classifier, examples, metric, {
  maxDemos: 4,
});

classifier.applyOptimization(result.optimizedProgram!);

Reach for bootstrap few-shot when:

AxGEPA

Use GEPA when you want Ax to evolve the strings that shape program behavior.

import { AxGEPA, ai, ax } from '@ax-llm/ax';

const llm = ai({
  name: 'openai',
  apiKey: process.env.OPENAI_APIKEY!,
});

const generator = ax(
  'ticket:string -> priority:class "low, normal, urgent", rationale:string'
);

const examples = [
  { ticket: 'Checkout is down for all EU users.', priority: 'urgent' },
  { ticket: 'Change the footer logo.', priority: 'low' },
];

const metric = ({ prediction, example }) =>
  prediction.priority === example.priority ? 1 : 0;

const optimizer = new AxGEPA({
  studentAI: llm,
});

const result = await optimizer.compile(generator, examples, metric, {
  bootstrap: true,
  maxMetricCalls: 24,
});

generator.applyOptimization(result.optimizedProgram!);

GEPA is a good fit when:

Bootstrap Behavior

When you pass bootstrap: true, Ax first runs the current program on the provided training tasks and turns only successful, high-scoring runs into demos.

That means:

Bootstrap in v1 works only from the tasks you provide. It does not synthesize new tasks.

Metrics and Judges

For plain programs, you typically pass a metric:

const metric = ({ prediction, example }) =>
  prediction.answer === example.answer ? 1 : 0;

For agents, you can usually omit it and rely on the built-in judge, as long as your tasks include strong criteria and, when useful, expectedActions or expectedOutput.

Add judgeAI when you want a stronger or separate judge model:

const result = await assistant.optimize(tasks, {
  judgeAI,
  bootstrap: true,
});

Choosing the Right Optimizer

Use AxBootstrapFewShot when:

Use AxGEPA when:

Use agent.optimize(...) when:

Practical Tips

Examples