GEPA helps to optimise LLM prompts rapidly and easily. This article explores the technique and the improvement I was able to achieve with it on a data extraction task.
Getting an LLM to do what you want mostly comes down to fiddling with the wording of the prompt you give it to yield the best results early on. You write an instruction, it gets something wrong, you add a line to cover that case, run it again, and something else breaks. After a while this begins to feel like iterative guesswork.
In my last blog, I explored benchmarks and LLM evaluation for comparing prompts; this detailed how scoring a prompt could be done against human labels and how failing cases could be observed to improve the prompt. GEPA aims to automate this loop.
What is GEPA?
GEPA stands for Genetic-Pareto and aims to improve a prompt by evolving a pool of them instead of editing one.
Genetic is the mutation step. GEPA scores a prompt from the pool, then hands a second model that prompt alongside its failures in full: the input, output, and labelled answer. That model writes a replacement. If the replacement scores higher, it joins the pool and can be mutated in turn.
Pareto is the selection step. For every example in the validation set, GEPA records which prompt scored highest on that example. A prompt is kept if it tops at least one example, even when its average is poor. Selecting on the average alone deletes prompts that are the only ones handling a particular case.
Rewrites are filtered before they cost much. GEPA scores the parent on a small batch of training examples, scores the rewrite on the same batch, and drops the rewrite unless it beats the parent there. Only survivors are evaluated against the full validation set.
GEPA is structured as a loop of the following:
Trying it out
The dataset I used for this was MultiWOZ 2.2, a set of conversations between a user and a booking assistant. I kept the restaurant ones, and the task was to read a conversation and write down what the user settled on such as the following:
INPUT ----- USER Is there an expensive African restaurant in town. SYSTEM Yes, The Bedouin in the city centre is a good, expensive restaurant. USER Excellent! I don't need a table right now, but if you could give me the address and phone number, that would be great. SYSTEM It is located at 100 Mill Road City Centre and the phone number is 01223367660. Is there anything else I can help you with? USER No thanks. That would be all for today. Have a nice day.
Not all of the prompt was up for grabs for GEPA. I made the output schema and rules fixed, so GEPA only rewrote the block of additional instructions in the middle, leaving a prompt structured as:
<slots> restaurant-area centre, east, north, south or west ... </slots>
<instructions> %INSTRUCTIONS% <-- the only part GEPA changes </instructions>
<output_contract> Return one JSON object. Every key must be a slot name... </output_contract>
Otherwise, it could rewrite the output format itself, which should be fixed – although if the reflector did try to break this, it should score worse and hence not be chosen, but that’s an experiment for another day.
Scoring was done per field: credit for each one the LLM got right, and a penalty for fields it left out, made up, or filled in with the wrong value. A wrong value counts twice, since it both misses the right answer and asserts a wrong one. This is called field F1 and is a number between 0 and 1.
MultiWOZ’s own dev and test sets aren’t interchangeable for this task as the same prompt scored a 19.0% slot error rate on one and 12.4% on the other. So I pooled them and dealt them out again, stratified by how many slots each conversation settles: 27 conversations for training, 45 for validation, 45 for a test set I left alone until the end. That’s 117 in total, which isn’t many.
What’s interesting is that you don’t need that much data for the training set because the reflector LLM only ever sees three at a time (by default); it’s looking for generalisable conventions that show up in one or two cases.
Size matters more on the validation set because that’s what decides which prompts survive. Too small and two things go wrong. LLM output varies between runs, so a prompt can be accepted for getting lucky rather than for being better. And a small set won’t cover the range of patterns in the data, so a prompt that only handles the common cases looks as good as one that handles all of them.
Running the Optimiser
I ran GEPA for 76 iterations and about 2,400 scoring calls, which produced 43 rewrites of the prompt, 6 of them an improvement on anything already in the pool. I used Gemini 2.5 Flash for all of the extraction calls and Claude Sonnet 5 for the reflection and prompt proposals.
GEPA produces a handy visualisation for the candidate tree of prompts where each node represents a prompt and its score on the validation set and the arrows show the parent node that a candidate prompt is a variant of. It shows how different options are kept open as GEPA is running. Nodes marked as “New pool best” are ones which a prompt scored the best for a particular example in the validation set:
If you hover over different nodes on the graphic below starting from candidate 0, you can see how the prompt evolves. In particular, look at the difference between candidates 0, 1 and 3 and how the prompt diverges at that first layer:
GEPA candidate tree: the first 12 prompts
Best so farNew pool bestOther
Candidate 0SEED
Score: 0.8912 | Parent(s): seed | Iteration: 0
Move onto this panel to scroll it
current_candidate
Extract the restaurant booking details from the conversation.
Candidate 1
Score: 0.8628 | Parent(s): 0 | Iteration: 6
Move onto this panel to scroll it
current_candidate
Record only the values the user and system explicitly settle on by the end of the
conversation, using the wording annotators would use.
General rules:
– Only include a slot if the conversation reaches a clear, settled value for it. Ignore
slots that are only mentioned in passing, rejected, changed later, or left unresolved
(use the final value if it changes during the conversation).
– If the user states they have no preference for a slot ("any", "doesn't matter", "you
choose", "surprise me", etc.) and the system then picks a specific value on the
user's behalf (rather than the user asking for that specific value), record that
slot as "dontcare" rather than the value the system happened to pick. The slot value
should reflect what the user actually asked for, not what the system booked.
– If the user explicitly requests or confirms a specific value for a slot (food type,
area, price range, name, day, time, number of people), record that specific value,
even if the system had earlier offered options.
– Normalize values to lowercase, singular/plain wording (e.g. "centre" not "Centre",
numbers as plain digits or words as spoken, e.g. "2" or "two" matching how it was
said).
– For restaurant-name, use the name as given, lowercased, without titles like "the"
unless it is part of the proper name.
– For restaurant-booktime, use the settled time in the form it was stated (e.g. "19:30"
or "7:30 pm" as spoken), preferring a 24-hour HH:MM form if the conversation implies
one.
– For restaurant-bookday and restaurant-bookpeople, only fill these if the user is
actually making or modifying a booking, not just asking about a restaurant.
– Do not invent, infer, or carry over values from world knowledge, defaults, or prior
turns that were not confirmed in this conversation.
– If nothing is settled for a slot, omit that slot entirely; do not guess or leave a
placeholder.
Candidate 2
Score: 0.8493 | Parent(s): 1 | Iteration: 7
Move onto this panel to scroll it
current_candidate
Record only the values the user and system explicitly settle on by the end of the
conversation, using the wording annotators would use.
General rules:
– Only include a slot if the conversation reaches a clear, settled value for it. Ignore
slots that are only mentioned in passing, rejected, changed later, or left unresolved
(use the final value if it changes during the conversation).
– restaurant-name is only settled when the user has committed to that restaurant as
their choice: they asked to book it, confirmed they want it, or otherwise treated it
as the place they are going with. A restaurant the system merely offers,
recommends, or names while answering a query (e.g. "there's a place called X" or
giving X's address/phone/postcode on request) is not settled unless the user goes on
to accept, book, or explicitly affirm that specific restaurant. Simply asking for
and receiving details (phone number, address, postcode) about a restaurant the
system suggested does not count as the user settling on that name — do not record
restaurant-name in that case.
– If the user ends the conversation with a thank-you / goodbye right after receiving
such details, without ever saying yes to booking or explicitly choosing that
restaurant by name, treat restaurant-name as unsettled.
– If the user states they have no preference for a slot ("any", "doesn't matter", "you
choose", "surprise me", etc.) and the system then picks a specific value on the
user's behalf (rather than the user asking for that specific value), record that
slot as "dontcare" rather than the value the system happened to pick. The slot value
should reflect what the user actually asked for, not what the system booked or
suggested.
– If the user explicitly requests, chooses, or confirms a specific value for a slot
(food type, area, price range, name, day, time, number of people), record that
specific value, even if the system had earlier offered options.
– Normalize values to lowercase, singular/plain wording (e.g. "centre" not "Centre",
numbers as plain digits or words as spoken, e.g. "2" or "two" matching how it was
said).
– For restaurant-name, use the name as given, lowercased, without titles like "the"
unless it is part of the proper name.
– For restaurant-booktime, use the settled time in the form it was stated (e.g. "19:30"
or "7:30 pm" as spoken), preferring a 24-hour HH:MM form if the conversation implies
one.
– For restaurant-bookday and restaurant-bookpeople, only fill these if the user is
actually making or modifying a booking, not just asking about a restaurant.
– Do not invent, infer, or carry over values from world knowledge, defaults, or prior
turns that were not confirmed in this conversation.
– If nothing is settled for a slot, omit that slot entirely; do not guess or leave a
placeholder.
Candidate 3
Score: 0.8874 | Parent(s): 0 | Iteration: 10
Move onto this panel to scroll it
current_candidate
Extract only the restaurant booking details that the user has explicitly stated and settled on by the end of the conversation.
Rules:
– A slot is settled only if the user (not the system) stated the value, or explicitly confirmed a value the system proposed on the user's behalf (e.g. agreeing "yes" to a specific area/food/price/day/time/people/name the system just offered as the choice to book).
– Do not infer or carry over a value merely because the system mentioned it while presenting options, recommendations, or availability information (e.g. a price range or cuisine mentioned only while describing a recommended restaurant, without the user confirming that attribute itself, is not settled). Only the attributes the user actually asked about, chose, or agreed to are settled.
– If the user accepts a specific named restaurant recommended by the system, only record the restaurant-name as settled (plus any other slots the user independently and explicitly confirmed); do not assume the restaurant's other attributes (price, area, food) became the user's settled preference unless the user separately stated or confirmed them.
– If the user changes their mind, record only the final, latest value for each slot.
– If a slot is never mentioned, mentioned only as rejected/unavailable, or left ambiguous/undecided, omit it entirely.
– Normalize values to lowercase and use the conventional short form: numbers as digits for people count, day names in full lowercase, times in 24-hour HH:MM format, and restaurant names/food/price/area exactly as spoken but lowercased and with whitespace collapsed.
– Do not invent, guess, or default any value not clearly stated or confirmed by the user.
Candidate 4
Score: 0.876 | Parent(s): 2 | Iteration: 11
Move onto this panel to scroll it
current_candidate
Record only the values the user and system explicitly settle on by the end of the
conversation, using the wording annotators would use.
General rules:
– Only include a slot if the conversation reaches a clear, settled value for it. Ignore
slots that are only mentioned in passing, rejected, or left unresolved.
– PERSISTENCE: once the user explicitly states a value for a slot (a food type, area,
price range, day, time, party size, or name they want), that value stays settled for
the rest of the conversation even if later turns move on to other topics, offer
alternatives, or fail to repeat it. Do not drop an earlier settled slot just because
it wasn't mentioned again. Only overwrite it if the user later gives a different
value for that same slot, or explicitly cancels/retracts it — in which case use the
final value.
– ATTRIBUTION: only record a value that the user themselves asked for, chose, or
explicitly confirmed as their preference. Do not record a slot value just because the
system mentions it while describing, recommending, or listing a restaurant (e.g. "it's
in the centre", "it serves Italian food", "it's a cheap restaurant", "there's a place
called X"). A fact stated by the system about a restaurant is not the same as the
user requesting or agreeing to that attribute. Choosing a restaurant by name does not
by itself settle its area, food type, or price range unless the user separately
stated or confirmed that attribute themselves.
– restaurant-name is only settled when the user has committed to that restaurant as
their choice: they asked to book it, confirmed they want it, or otherwise treated it
as the place they are going with. A restaurant the system merely offers, recommends,
or names while answering a query (e.g. "there's a place called X" or giving X's
address/phone/postcode on request) is not settled unless the user goes on to accept,
book, or explicitly affirm that specific restaurant. Simply asking for and receiving
details (phone number, address, postcode) about a restaurant the system suggested
does not count as settling that name.
– If the user ends the conversation with a thank-you / goodbye right after receiving
such details, without ever saying yes to booking or explicitly choosing that
restaurant by name, treat restaurant-name as unsettled.
– If the user states they have no preference for a slot ("any", "doesn't matter", "you
choose", "surprise me", etc.) and the system then picks a specific value on the
user's behalf (rather than the user asking for that specific value), record that
slot as "dontcare" rather than the value the system happened to pick. The slot value
should reflect what the user actually asked for, not what the system booked or
suggested.
– If the user explicitly requests, chooses, or confirms a specific value for a slot
(food type, area, price range, name, day, time, number of people), record that
specific value, even if the system had earlier offered options, and even if a later
part of the conversation shifts to a different slot without repeating this one.
– Normalize values to lowercase, singular/plain wording (e.g. "centre" not "Centre",
numbers as plain digits or words as spoken, e.g. "2" or "two" matching how it was
said).
– For restaurant-name, use the name as given, lowercased, without titles like "the"
unless it is part of the proper name.
– For restaurant-booktime, use the settled time in the form it was stated (e.g. "19:30"
or "7:30 pm" as spoken), preferring a 24-hour HH:MM form if the conversation implies
one.
– For restaurant-bookday and restaurant-bookpeople, only fill these if the user is
actually making or modifying a booking, not just asking about a restaurant.
– Do not invent, infer, or carry over values from world knowledge, defaults, or prior
turns that were not confirmed in this conversation. Persistence (above) applies only
to values the user themselves explicitly stated earlier in this same conversation.
– If nothing is settled for a slot, omit that slot entirely; do not guess or leave a
placeholder.
Candidate 5
Score: 0.8857 | Parent(s): 3 | Iteration: 12
Move onto this panel to scroll it
current_candidate
Extract only the restaurant booking details that the user has explicitly stated and settled on by the end of the conversation.
Rules:
– A slot is settled only if the user (not the system) stated the value, or explicitly confirmed a value the system proposed on the user's behalf (e.g. agreeing "yes" to a specific area/food/price/day/time/people/name the system just offered as the choice to book).
– Do not infer or carry over a value merely because the system mentioned it while presenting options, recommendations, availability, or contact/booking details (e.g. a price range, area, or food type mentioned only while describing or answering a question about a restaurant, without the user separately stating or agreeing to that attribute as their preference, is not settled).
– If the system names a specific restaurant (as a recommendation or as the answer to a search) and the user continues the conversation without objecting, asks follow-up questions about it (e.g. requesting its phone number, address, or price range), or thanks the system and ends the conversation, that alone does NOT settle restaurant-name. Only record restaurant-name if the user explicitly chooses, requests booking of, or affirmatively confirms that specific restaurant as the one they want.
– If the user accepts or books a specific named restaurant, record only the restaurant-name as settled (plus any other slots the user independently and explicitly confirmed); do not assume the restaurant's other attributes (price, area, food) became the user's settled preference unless the user separately stated or confirmed them.
– Asking the system for information about an attribute (e.g. "what is their price range?") is a request for information, not a statement of preference, and does not settle that slot unless the user then confirms or restates it as their choice.
– If the user changes their mind, record only the final, latest value for each slot.
– If a slot is never mentioned, mentioned only as rejected/unavailable, or left ambiguous/undecided, omit it entirely.
– Normalize values to lowercase and use the conventional short form: numbers as digits for people count, day names in full lowercase, times in 24-hour HH:MM format, and restaurant names/food/price/area exactly as spoken but lowercased and with whitespace collapsed.
– Do not invent, guess, or default any value not clearly stated or confirmed by the user.
Candidate 6
Score: 0.858 | Parent(s): 5 | Iteration: 14
Move onto this panel to scroll it
current_candidate
Extract only the restaurant booking details that the user has explicitly stated and settled on by the end of the conversation.
Rules:
– A slot is settled only if the user (not the system) stated the value, or explicitly confirmed a value the system proposed on the user's behalf (e.g. agreeing "yes" to a specific area/food/price/day/time/people/name the system just offered as the choice to book).
– If the system recommends or looks up a specific restaurant and states one or more of its attributes (price range, area, food type) as facts about that restaurant, and the user then accepts, books, or confirms that restaurant (e.g. "yes, that sounds great", "book it", "yes please"), treat that acceptance as confirming not only the restaurant-name but also every attribute of that restaurant the system just stated, even if the user does not repeat the attribute values themselves. Record restaurant-name plus those attributes as settled.
– If the system names a specific restaurant and the user continues the conversation without objecting, asks only follow-up questions about it (e.g. requesting its phone number, address, or postcode), or thanks the system and ends the conversation — without any acceptance, booking request, or affirmative confirmation of the restaurant as their choice — then nothing about that restaurant (name or attributes) is settled.
– Do not infer or carry over a value merely because the system mentioned it while presenting multiple options, general availability, or answering an unrelated question, without the user accepting a specific restaurant or separately stating/confirming that attribute as their preference.
– Asking the system for information about an attribute (e.g. "what is their price range?") is a request for information, not a statement of preference, and does not settle that slot unless the user then confirms or restates it as their choice.
– If the user changes their mind, record only the final, latest value for each slot.
– If a slot is never mentioned, mentioned only as rejected/unavailable, or left ambiguous/undecided, omit it entirely.
– Normalize values to lowercase and use the conventional short form: numbers as digits for people count, day names in full lowercase, times in 24-hour HH:MM format, and restaurant names/food/price/area exactly as spoken but lowercased and with whitespace collapsed.
– Do not invent, guess, or default any value not clearly stated or confirmed by the user.
Candidate 7NEW POOL BEST
Score: 0.8928 | Parent(s): 5 | Iteration: 15
Move onto this panel to scroll it
current_candidate
Extract the restaurant-booking slots that the user has settled on by the end of the conversation, matching how a human annotator would fill the state.
What counts as "settled":
– The user directly states a value for a slot (e.g. names an area, cuisine, price band, day, time, party size, or restaurant).
– The user confirms a value that the system offers or proposes on the user's behalf (e.g. saying "yes"/"that works" to a specific area, food, price, day, time, people-count, or restaurant the system just suggested as the one to use or book).
– The user proposes a specific value as a yes/no question about the restaurant currently under discussion (e.g. asking "is it cheap?", "is that in the centre?") and the system confirms it, and the user does not contradict or reject that confirmation afterward. Treat the confirmed value as settled for that slot.
– The user explicitly declines to state a preference for a slot (e.g. "I don't care", "any is fine", "no preference", "it doesn't matter") — record that slot's value as "dontcare".
Restaurant name:
– Record restaurant-name whenever the system offers a specific, single named restaurant as the answer to the user's request (a search result or a recommendation) and the user goes on to treat it as their chosen restaurant — by asking for its details (phone, address, postcode, price, etc.), by requesting or accepting a booking for it, or by thanking the system and ending the conversation without objection.
– Do NOT record restaurant-name if the user rejects that restaurant, asks the system to look for a different one, or the conversation ends before any specific restaurant is ever named.
– If several different restaurants are named over the course of the conversation, keep only the last one the user settled on by the above test.
Other attributes of an accepted restaurant:
– Do not assume a restaurant's price range, area, or food type became the user's settled preference just because the system mentioned that attribute while describing, recommending, or answering a factual question about the restaurant (e.g. giving its price range, address, or cuisine in response to a plain informational request).
– Such an attribute only becomes settled if the user separately states it, confirms it as their choice, or it is confirmed via a user-proposed yes/no question as described above.
– Merely asking a neutral factual question ("what is the price range?", "what area is that in?") without proposing a specific value is a request for information and does not settle the slot on its own.
General rules:
– If the user changes their mind, keep only the final, latest value for each slot.
– Omit a slot entirely if it is never mentioned, mentioned only as rejected/unavailable, or left ambiguous/undecided, and it was never confirmed by any of the mechanisms above.
– Do not invent, guess, or default any value not clearly stated, confirmed, or marked "dontcare" as described above.
– Normalize values: lowercase everything; collapse extra whitespace; write people-count as digits; write day names in full (e.g. "monday"); write times in 24-hour HH:MM format; write food/price/area/name exactly as spoken but lowercased, aside from the "dontcare" convention above.
Candidate 8
Score: 0.8837 | Parent(s): 7 | Iteration: 16
Move onto this panel to scroll it
current_candidate
Extract the restaurant-booking slots that the user has settled on by the end of the conversation, matching how a human annotator would fill the state.
What counts as "settled":
– The user directly states a value for a slot (e.g. names an area, cuisine, price band, day, time, party size, or restaurant).
– The user confirms a value that the system offers or proposes on the user's behalf (e.g. saying "yes"/"that works" to a specific area, food, price, day, time, people-count, or restaurant the system just suggested as the one to use or book).
– The user proposes a specific value as a yes/no question about the restaurant currently under discussion (e.g. asking "is it cheap?", "is that in the centre?") and the system confirms it, and the user does not contradict or reject that confirmation afterward. Treat the confirmed value as settled for that slot.
– The user explicitly declines to state a preference for a slot (e.g. "I don't care", "any is fine", "no preference", "it doesn't matter") — record that slot's value as "dontcare".
– If the user asks the system to pick/choose/decide on their behalf for a given slot (e.g. "pick one for me", "you choose the type of food", "surprise me"), that also counts as declining a preference — record that slot's value as "dontcare", even if the system's subsequent choice happens to name a specific value. The system's chosen value does not become the user's settled preference merely because the user accepted the resulting restaurant; only the "dontcare" is settled for that slot unless the user later separately states or confirms a specific value for it.
Restaurant name:
– Record restaurant-name whenever the system offers a specific, single named restaurant as the answer to the user's request (a search result or a recommendation) and the user goes on to treat it as their chosen restaurant — by asking for its details (phone, address, postcode, price, etc.), by requesting or accepting a booking for it, or by thanking the system and ending the conversation without objection.
– Do NOT record restaurant-name if the user rejects that restaurant, asks the system to look for a different one, or the conversation ends before any specific restaurant is ever named.
– If several different restaurants are named over the course of the conversation, keep only the last one the user settled on by the above test.
Other attributes of an accepted restaurant:
– Do not assume a restaurant's price range, area, or food type became the user's settled preference just because the system mentioned that attribute while describing, recommending, or answering a factual question about the restaurant (e.g. giving its price range, address, or cuisine in response to a plain informational request).
– Such an attribute only becomes settled if the user separately states it, confirms it as their choice, marks it "dontcare" per the rules above, or it is confirmed via a user-proposed yes/no question as described above.
– Merely asking a neutral factual question ("what is the price range?", "what area is that in?") without proposing a specific value is a request for information and does not settle the slot on its own.
– If the user leaves a slot entirely up to the system (explicitly or by asking the system to pick), record "dontcare" for that slot even though a specific restaurant with a specific attribute value ends up being accepted — do not copy the accepted restaurant's attribute as the settled value.
General rules:
– If the user changes their mind, keep only the final, latest value for each slot.
– Omit a slot entirely if it is never mentioned, mentioned only as rejected/unavailable, or left ambiguous/undecided, and it was never confirmed or marked "dontcare" by any of the mechanisms above.
– Do not invent, guess, or default any value not clearly stated, confirmed, or marked "dontcare" as described above.
– Normalize area values to one of: centre, east, north, south, west. Phrases like "city centre", "town centre", "downtown", "center of town" all normalize to "centre"; strip filler words such as "city", "town", "part of town", "area" from the area value.
– Normalize values generally: lowercase everything; collapse extra whitespace; write people-count as digits; write day names in full (e.g. "monday"); write times in 24-hour HH:MM format; write food/price/name exactly as spoken but lowercased, aside from the "dontcare" convention above.
Candidate 9NEW POOL BEST
Score: 0.9105 | Parent(s): 4 | Iteration: 17
Move onto this panel to scroll it
current_candidate
Record only the values the user and system explicitly settle on by the end of the
conversation, using the wording annotators would use.
General rules:
– Only include a slot if the conversation reaches a clear, settled value for it. Ignore
slots that are only mentioned in passing, rejected, or left unresolved.
– PERSISTENCE: once a value for a slot is settled (a food type, area, price range, day,
time, party size, or restaurant name), that value stays settled for the rest of the
conversation even if later turns move on to other topics, offer alternatives, or fail
to repeat it. Do not drop an earlier settled slot just because it wasn't mentioned
again. Only overwrite it if the user later gives a different value for that same
slot, or explicitly cancels/retracts it — in which case use the final value.
– ATTRIBUTION for food/area/price/day/time/people: only record a value that the user
themselves asked for, chose, or explicitly confirmed as their preference. Do not
record a slot value just because the system mentions it while describing a
restaurant (e.g. "it's in the centre", "it serves Italian food", "it's a cheap
restaurant"). A fact stated by the system about a restaurant is not the same as the
user requesting or agreeing to that attribute. Choosing a restaurant by name does not
by itself settle its area, food type, or price range unless the user separately
stated or confirmed that attribute themselves.
– restaurant-name: record the name of whichever specific restaurant the conversation
ends up centered on, as long as the user did not reject it or ask for a different
one. This includes any of the following:
* the user stating the name themselves as the restaurant they are looking for, want
to book, or want information about;
* the system offering, recommending, or naming a specific restaurant (e.g. in
response to the user's stated preferences, or when the user asks for a place with
certain criteria), after which the user continues the conversation about that same
restaurant — asking for its address, phone number, postcode, confirming
reservation details, or simply proceeding to end the conversation — without
rejecting it or asking for an alternative.
Only leave restaurant-name unsettled if: no specific restaurant was ever named in the
conversation, or the user explicitly rejected the offered restaurant, asked for a
different one, or the system offered multiple restaurants and the user never
indicated which (if any) they were continuing with.
If the user rejects one restaurant and a new one is subsequently offered or named and
the conversation continues on that one without rejection, use the later restaurant.
– If the user states they have no preference for a slot ("any", "doesn't matter", "you
choose", "surprise me", etc.) and the system then picks a specific value on the
user's behalf (rather than the user asking for that specific value), record that
slot as "dontcare" rather than the value the system happened to pick. The slot value
should reflect what the user actually asked for, not what the system booked or
suggested. (This dontcare rule does not apply to restaurant-name; see above.)
– If the user explicitly requests, chooses, or confirms a specific value for a slot
(food type, area, price range, day, time, number of people), record that specific
value, even if the system had earlier offered options, and even if a later part of
the conversation shifts to a different slot without repeating this one.
– Normalize values to lowercase, singular/plain wording (e.g. "centre" not "Centre",
numbers as plain digits or words as spoken, e.g. "2" or "two" matching how it was
said).
– For restaurant-name, use the name as given, lowercased, without titles like "the"
unless it is part of the proper name.
– For restaurant-booktime, use the settled time in the form it was stated (e.g. "19:30"
or "7:30 pm" as spoken), preferring a 24-hour HH:MM form if the conversation implies
one.
– For restaurant-bookday and restaurant-bookpeople, only fill these if the user is
actually making or modifying a booking, not just asking about a restaurant.
– Do not invent, infer, or carry over values from world knowledge, defaults, or prior
turns that were not confirmed in this conversation. Persistence (above) applies only
to values settled earlier in this same conversation.
– If nothing is settled for a slot, omit that slot entirely; do not guess or leave a
placeholder.
Candidate 10
Score: 0.8868 | Parent(s): 3 | Iteration: 19
Move onto this panel to scroll it
current_candidate
Extract only the restaurant booking details that the user has explicitly stated and settled on by the end of the conversation.
Rules:
– A slot is settled only if the user (not the system) stated the value, or explicitly confirmed a value the system proposed on the user's behalf (e.g. agreeing "yes" to a specific area/food/price/day/time/people/name the system just offered as the choice to book).
– Do not infer or carry over a value merely because the system mentioned it while presenting options, recommendations, or availability information (e.g. a price range, area, or cuisine mentioned only while describing a recommended restaurant, without the user confirming that attribute itself, is not settled). Only the attributes the user actually asked about, chose, or agreed to are settled.
– If the user accepts a specific named restaurant recommended by the system, only record the restaurant-name as settled (plus any other slots the user independently and explicitly confirmed); do not assume the restaurant's other attributes (price, area, food) became the user's settled preference unless the user separately stated or confirmed them.
– If the user explicitly states they have no preference for a slot (e.g. "any", "it doesn't matter", "surprise me", "you choose" in response to a system question about that specific slot), record that slot's value as "dontcare". This applies even if the system then picks a specific value and the user only confirms the resulting restaurant/name, not the attribute itself.
– If the user changes their mind, record only the final, latest value for each slot.
– If a slot is never mentioned, mentioned only as rejected/unavailable, or left ambiguous/undecided, omit it entirely.
– Restaurant names: record the name exactly as the user or system states it, lowercased with whitespace collapsed, but strip a leading definite article ("the") from the name.
– Areas: normalize to one of centre, east, north, south, west. Phrases like "city centre", "town centre", "downtown", "in town" all normalize to "centre"; do not include extra words like "city" or "town" in the value.
– Normalize other values to lowercase and use the conventional short form: numbers as digits for people count, day names in full lowercase, times in 24-hour HH:MM format, and food/price exactly as spoken but lowercased and with whitespace collapsed.
– Do not invent, guess, or default any value not clearly stated, confirmed, or explicitly left open ("dontcare") by the user.
Candidate 11BEST SO FAR
Score: 0.9115 | Parent(s): 5 | Iteration: 20
Move onto this panel to scroll it
current_candidate
Extract only the restaurant booking details that the user has settled on by the end of the conversation, following the same conventions MultiWOZ annotators used.
Rules:
– A slot is settled if the user (a) explicitly stated the value, (b) explicitly confirmed a value the system proposed, or (c) continued the conversation after the system offered a specific value in answer to their request without rejecting it or asking for a different alternative.
– Restaurant name: if the system names a specific restaurant as the answer to the user's search or as a recommendation, and the user does not reject it or ask for a different one — e.g. the user asks a follow-up question about it (phone number, address, postcode, price range, area), asks to book it, or simply thanks the system and ends the conversation — treat that restaurant as the settled restaurant-name. Only omit restaurant-name if the user rejects the suggestion, asks for an alternative, or the conversation ends with no restaurant ever offered or chosen.
– Persistence: once the user has stated a preference for a slot (area, food, price, day, time, people), that value stays settled for the rest of the conversation even if a later search for that combination fails, the system reports no matching results, or the user goes on to change or narrow a different slot. Only overwrite it if the user explicitly states a new value for that same slot later on.
– Do not infer or invent a value merely because the system mentioned it while presenting options, availability, or contact/booking details, unless it falls under the persistence or acceptance rules above (i.e. it must trace back to something the user stated, confirmed, or accepted as described above).
– Asking the system for information about an attribute (e.g. "what is their price range?") is a request for information, not a statement of preference, and does not by itself settle that slot — unless the user then restates or confirms it as their own choice.
– When the user accepts, books, or is offered and does not reject a specific named restaurant, do not assume its other attributes (price, area, food) became the user's settled preference unless the user separately stated, confirmed, or had already settled them earlier in the conversation via the persistence rule.
– If the user changes their mind, record only the final, latest value for each slot.
– If a slot is never mentioned, mentioned only as rejected/unavailable, or left ambiguous/undecided, omit it entirely.
– Normalize values to lowercase and use the conventional short form: numbers as digits for people count, day names in full lowercase, times in 24-hour HH:MM format, and restaurant names/food/price/area exactly as spoken but lowercased and with whitespace collapsed.
– Do not invent, guess, or default any value not clearly stated, confirmed, or accepted by the user as described above.
The Results
The run took the one-line prompt from 0.88 to 0.95 field F1 on the test set I’d left alone until the end. The best prompt on the validation set came near the end of the run, but it scored 0.94 on the test set. The one that scored 0.95 turned up about a third of the way in.
Seed prompt
GEPA optimised prompt
Change
Fields it got Right
217
215
-2
Fields it got wrong or left out
11
13
+2
Fields it made up
24
2
-22
This shows us that the optimised prompt didn’t help to improve reading the conversations at all. What it stopped doing was making things up, and that was essentially the whole gain.
This makes sense when looking at the final prompt generated. I started with 61 characters and GEPA finished with 6,400 – most of which are rules about when not to fill a field. GEPA will try to optimise whatever scoring mechanism you give it which means in this case where I used field F1 it clearly found the easiest path to do that was through adding rules to reduce hallucinated fields.
In the image above, we can see how the prompt improved at extraction accuracy on the validation set over time, with major diminishing returns after 750 calls, where the difference in prompts being “better” could be within the noise of LLM non-determinism.
We also see rapid initial improvements, which is where GEPA seems to shine. This makes it very good for bootstrapping new prompts from essentially nothing for new LLM use cases, but very slow and expensive to squeeze out the last few percentage points.
All of your measurements improve in accuracy when you increase the number of test cases in the validation and test sets, but this is also expensive as each is an additional LLM API call.
Summary & Insights
Your scoring/evaluation mechanism needs to match your exact goals. GEPA doesn’t know what a better prompt means, only what the score rewards, so anything you care about that isn’t included in this score might be sacrificed to improve it.
For example, if you don’t include shortness of prompt in the score, GEPA will happily keep adding more to the prompt to optimise accuracy and anything that is in the score.
GEPA speeds up the initial prompt engineering process, and leaves it in a human-readable state to be hand-tuned for the last few percentage points, or otherwise you can become constrained on data, and it becomes rather expensive.
Spending on the reflector model is where it matters most. I used Claude Sonnet 5 for this experiment, but perhaps a more powerful model would yield better results.
GEPA doesn’t replace the human expert; it should be thought of as an exciting optimisation technique that is a tool for experts to start a task with.
Leave a Reply