Skip to content

feat(core): few-shot demos and optimizers (LabeledFewShot, BootstrapFewShot) - #22

Merged
ardada2468 merged 2 commits into
mainfrom
feat/few-shot-optimizers
Aug 22, 2026
Merged

ardada2468 merged 2 commits into
mainfrom
feat/few-shot-optimizers

Conversation

@ardada2468

Copy link
Copy Markdown
Owner

What

Predict had no few-shot support, and Example was exported with zero call sites anywhere in the repo. This wires both up and adds the optimizers that make "TypeScript DSPy" a description rather than an homage.

1. Demos in Predict

new Predict(Sig, { lm, demos }) renders Examples into the prompt as worked examples before the real input. The original (signature, lm) form still works — the second argument is discriminated structurally, and an object carrying only half an ILanguageModel is rejected loudly rather than silently falling back to the globally configured model.

withDemos() and withLM() return configured copies, preserving the concrete subclass, so ChainOfThought.withDemos() returns a ChainOfThought and an optimizer never mutates the student it was handed.

Demos render in whichever shape the reply is expected to take: labelled field: value for a text provider (exactly what parseOutput() reads back), JSON for a provider with native structured output — where constrained decoding means labelled examples would model a shape the model is forbidden to emit. All three shipped providers take the structured path, so this is the common case, not an edge one.

A prompt built with no demos is byte-for-byte what it was before; parsing.test.ts is untouched and green.

2. LabeledFewShot

Selects k of your own labelled examples. No model calls, so compiling is free and instant.

3. BootstrapFewShot

Runs the module over a labelled trainset, scores each attempt with a metric, and promotes the runs that passed into demos. An optional teacher model generates the demos that a cheaper student then imitates — you pay for the strong model once, at compile time.

  • Deterministic given a seed. Seeded shuffle (mulberry32), results collected in input order, and the batch boundary that enables early stopping is also what guarantees the successes collected so far really are the first ones in trainset order.
  • Bounded concurrency, and it stops as soon as it has maxBootstrappedDemos — a 500-row trainset does not cost 500 teacher calls to keep 4 demos.
  • Failures are skipped, not fatal. A provider error, a reply that fails validation, or a throwing metric is reported as an error event and skipped. A throwing onProgress callback is swallowed too — an observer must not be able to lose a compile.
  • maxBootstrappedDemos: 0 with maxLabeledDemos set is a labels-only compile that makes no model calls at all.
  • no-console respected: progress goes through an optional callback.

The Metric type is defined locally in optimizers/types.ts rather than imported from the sibling evaluate/ PR, so the two can land in either order and be unified in a follow-up.

Verification

  • npm run build / lint / typecheck / format:check / verify:packaging all clean.
  • 229 tests pass, including predict.test.ts, chain-of-thought.test.ts, and parsing.test.ts unchanged.
  • A throwaway consumer script (deleted before commit) imported from the built @ts-dspy/core package and asserted that a bootstrapped module's next prompt contains the demos whose metric passed and none of the rows that failed, that two compiles with the same seed produce identical demos, and that a teacher does the compile-time work while the student carries the result.

Docs

New section 21 #optimizers in site/docs.html, plus its TOC entry. No existing section renumbered. README's DSPy framing now mentions that optimization exists. examples/optimizer.ts and an example:optimizer npm script.

🤖 Generated with Claude Code

ardada2468 and others added 2 commits August 22, 2026 13:42
Predict now accepts demos, and two optimizers turn a labelled trainset into
them, so a program improves from data rather than from prompt edits.

- Predict accepts `{ lm, demos }` alongside the existing `(signature, lm)`
  form, plus `withDemos()` / `withLM()` for configured copies.
- buildPrompt renders demos as worked examples: labelled `field: value` on
  the text path, JSON on the structured-output path, so a demo always models
  the shape the reply is allowed to take. A prompt with no demos is
  byte-for-byte what it was before.
- LabeledFewShot selects k of your own labels with no model calls.
- BootstrapFewShot runs the trainset, scores each attempt with a metric, and
  promotes the runs that passed; an optional teacher model generates demos a
  cheaper student then imitates. Bounded concurrency, early stop once enough
  demos are collected, failing rows skipped, progress via callback.
- Both are deterministic given a seed.

Adds examples/optimizer.ts with an `example:optimizer` script, and docs site
section 21.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
# Conflicts:
#	package.json
#	packages/core/src/index.ts
#	packages/core/src/modules/predict.ts
#	packages/core/src/utils/parsing.ts
#	site/docs.html
@ardada2468
ardada2468 merged commit a3ce924 into main Aug 22, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant