Data in. Better prompt out.

This is the prompt-learning loop: dataset → objective → optimizer → validation. It needs three things from you — labeled examples, a starter prompt and an objective. We'll walk through prompt compression, but the same loop optimizes anything you can score.

1

Start with labeled data

A dataset is a list of inputs with known answers. Here is a name-extraction set: passages of text and the people mentioned in them.

inputs.textanswer
"After the merger, Priya Natarajan moved the Denver office to a four-day week; Marcus Hale objected in the March board meeting."["Priya Natarajan", "Marcus Hale"]
"Rainfall in Portland exceeded the September average, the National Weather Service reported."[]
"Dr. Elena Vasquez will present the findings; Tuesday's session is chaired by Tom Bright of Unilever."["Elena Vasquez", "Tom Bright"]
"The Lakers signed Charles Okafor to a two-year deal, sources told Reuters."["Charles Okafor"]

Run a prompt over the dataset and score each output against the answer. Now every prompt has a number — or a vector of numbers. That's what the optimizer sees. It never needs to understand the task; it only needs (prompt, score) pairs.

promptf1template_tokens
Extract the full names of all people mentioned in the text below. Return only real people (not places, companies, months …). Output JSON: {"names": [...]}0.9797
List every person's full name in the text as JSON {"names": [...]}. Skip organizations and places.0.9631
People named, JSON {"names":[]}0.939
Names:0.612
2

Give it a starter prompt and an objective

The starter prompt is the root of the search tree — usually whatever you have in production today. The objective says what "better" means. Scores are vectors; the objective is a small function that turns a vector into a scalar, so it's cheap to swap.

Prompt compression

Maximize accuracy minus a per-token penalty, or hold accuracy above a floor and minimize tokens. f1 − 0.001·template_tokens, or a token budget that tightens each round.

Accuracy

Exact match, set-F1, or an LLM judge asked "is this equivalent to the reference?" Pure quality, no cost term.

Format & reliability

Fraction of outputs that parse as valid JSON, follow a schema, or stay within a length limit. Great for tool-call formatters.

Latency & cost

Output tokens, prompt tokens, wall time. Combine with a quality metric to trade them off explicitly.

from bpto import AnthropicClient, Dataset, LinearObjective, Task, combine, template_tokens, token_count
from tasks.compression import Entities, set_f1

task = Task(
    root=open("prompt.txt").read(),                  # your current prompt, with {text} placeholder
    description="extracts the names of all people mentioned in a passage",
    dataset=Dataset.from_jsonl("train.jsonl"),       # {"inputs": {"text": ...}, "answer": [...]}
    schema=Entities,
    scorer=combine(set_f1(), template_tokens(), token_count()),
    objective=LinearObjective(f1=1.0, template_tokens=-0.002),
    client=AnthropicClient("claude-opus-5"),
)
3

Search

The optimizer grows a tree. An LLM proposes rewrites of a node (random variants, or directed: "make it shorter", "be more precise", or a reflection on the examples the parent got wrong). Each child is evaluated on the dataset. A selector decides which node to expand next — greedy, a Pareto pool, or a Bayesian surrogate over prompt embeddings that predicts where the good children are.

root · 97 tokf1 0.97 31 tokf1 0.96 58 tokf1 0.97 22 tokf1 0.91 14 tokf1 0.95 9 tokf1 0.93 ★ best 12 tokf1 0.84 19 tokf1 0.90 selector: expand next ↓
A prompt tree. Nodes are prompts scored on the dataset; edges are LLM rewrites. The selector picks which node to expand next — that choice is where the sample efficiency comes from. Why that's hard →
4

Read the result off the Pareto front

For a two-objective problem like compression, the answer isn't one prompt — it's a front. bpto keeps every non-dominated (tokens, accuracy) pair so you can choose the operating point your product needs.

Before · 97 tokens · held-out F1 0.97
You are an information extraction system. Read the passage below carefully and extract the full names of every person who is mentioned. Include each person only once, preserve the order in which they first appear, and do not include organisations, places, or pronouns. Titles such as Dr. or Professor are not part of the name. If no people are mentioned, return an empty list.

Passage:
{text}
After · 6 tokens · held-out F1 0.965
Extract human names from: {text}
97
6
Measured, not assumed. In the compression v2 run (12 seeds × 2,000 rollouts, 100 training / 200 held-out examples) both search strategies compressed the 97-token root to 6–29 tokens; the best seed reached 6 tokens at held-out F1 0.965 vs 0.984 for the original. Full tables and front plots on the findings page. (Table prompts above are illustrative; the before/after pair is real.)

It's not just compression

Nothing above was specific to shortening prompts. The optimizer sees a root, a dataset, a scorer and an objective. Change the objective and the same tree search does something else:

Completions are cached on (prompt, config, schema), so re-scoring the whole tree under a new objective costs nothing.

Prompt learning for a whole system

Real products aren't one prompt. A ReAct-style agent is a loop of several prompts, each with its own job, each run several times per task. Every box below is a prompt you can optimize — with its own objective — using the same loop.

System prompt obj: task accuracy Planner / thought obj: steps to solve, tokens Tool-call formatter obj: % valid JSON calls Tool (not a prompt) Observation summarizer obj: compress, keep facts Final answer obj: LLM-judge score loop, several times per task
A ReAct loop. Five prompts, five objectives, one end-to-end metric. The summarizer is the compression target — it runs once per tool call, so its tokens compound fastest.

How you optimize it

Because the optimizer only ever sees (prompt, score), a module's "prompt" can be anything text-shaped: a system prompt, a few-shot block, a tool description, or the instructions inside a chain-of-thought template.

Today all of this runs as the open-source bpto library. The promptcompression.ai Studio will put the same steps — upload data, set a starter prompt and objective, search, pick from the front — behind a point-and-click interface.