← All AI Engineer talks

AI Engineer Europe 2026

Judge the Judge: Building LLM Evaluators That Actually Work with GEPA — Mahmoud Mabrouk, Agenta AI

Read the talk

Judge the Judge: Calibrating LLM Evaluators with GEPA

A customer-support evaluator learns airline policy from annotated failures, revealing how seed prompts, reflection, candidate diversity and data quality shape reliable evaluation.

From a talk by Mahmoud Mabrouk

Before you start: Familiarity with LLM prompts, agent tool calls, training and validation splits, and basic classification metrics will help with the notebook walkthrough.

The monitor says everything is fine

An agent is in production, and the team adds a hallucination judge to monitor reliability. The dashboard looks healthy. Customers complain anyway, and the traces confirm that the agent is failing. Under the hood, the evaluator’s prompt amounts to: given an LLM output, decide whether it is a hallucination, and make no mistakes. The instruction supplies neither the missing facts nor the criteria needed to recognize a failure.

Slide titled “Let's make an LLM-as-a-judge” showing a prompt asking whether an LLM output is a hallucination, followed by “MAKE NO MISTAKES!” and an output placeholder.
A minimal hallucination judge prompt: “MAKE NO MISTAKES!”

An evaluator needs a standard of correctness that matches the application. Mahmoud Mabrouk’s workshop builds toward that standard by calibrating an LLM judge against annotations, using GEPA to optimize its prompt. Here, calibration means making the judge’s decisions agree with the reference judgments; it is not a claim about calibrated probability estimates.

0:000:16
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

0:00 · section reference included

Evaluation determines how fast the application can improve

Offline development follows a familiar loop: change the prompt or harness, run evaluations, retain useful changes, and repeat. Human review can provide a strong signal, but reviewing the entire test set at every iteration is slow. An automated judge speeds up the loop only if its decisions track the judgments that matter. Otherwise, the team moves faster without knowing whether the application improved.

Online evaluation extends the same requirement to production. A judge aligned with business goals can help reveal regressions, improvements and changes in how users interact with an agent. Those observations can feed a data flywheel: inspect traces, turn edge cases into new evaluations, optimize the harness, and observe again. If both the harness and its evaluators can improve from new annotations, more of that cycle becomes amenable to automation.

Slide listing three evaluation uses beside a trophy and circular arrows connecting “Optimize Harness,” “Add New Evals,” and a partially obscured observation box.
Offline evals, online evals, and the data flywheel.

Mabrouk introduces himself as Agenta’s co-founder and CEO, with a machine-learning background that includes computational biology and protein structure prediction. Agenta brings together observability, prompt management and evaluation; his current work includes sampling and automatic optimization. The practical exercise is an airline customer-support judge, taken through metric design, data curation, annotation, optimization and validation. The workshop repository accompanies the notebook walkthrough.

1:181:39
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

1:18 · section reference included

A cancellation can succeed and still violate policy

The exercise uses airline conversations from the τ-bench benchmark family. The agent can manage reservations and retrieve flight and user information, but those tools operate under detailed rules about what it may change and when. A successful tool call is therefore insufficient evidence of a successful interaction: the agent may cancel a reservation without first establishing that it qualifies for cancellation.

Mabrouk describes an initial collection of 599 traces, approximately 62% compliant and 38% non-compliant, generated across multiple models and trials. Assertion-based results are converted into trace-level verdicts with explanations. In the cancellation example, the useful annotation identifies both the outcome—non-compliant—and the missing prerequisite: checking the airline’s cancellation rules before approving the request. The policy is complex, and Mabrouk describes the collection as imperfect demonstration data.

5:476:08
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

5:47 · section reference included

Derive the metrics from observed errors

The workflow has four steps: design the metrics, annotate the data, optimize the judge, and validate the result. The first step requires application knowledge. A generic hallucination score does not capture every way an airline agent can fail; a subject-matter expert needs to examine actual conversations and identify what went wrong. Mabrouk points to Hamel Husain’s error-analysis workflow: begin with open-ended comments on trajectories, then group recurring failures into categories.

The Agenta demonstration produces four categories:

Evaluation axisWhat the reviewer checks
Policy adherenceWhether actions obey the airline’s rules
Response styleWhether the response follows the expected style
Information deliveryWhether the customer receives necessary information
Tool callsWhether tools are called correctly

Information delivery is distinct from performing the operation: an agent might make a change and fail to tell the customer. Each category becomes a separate judge, keeping the decision narrower than an all-purpose success score.

Error Analysis slide with an open annotation dropdown listing Policy Adherence, Response Style, Information Delivery, and Miscalled tools.
Error analysis groups failures into specific categories.

Use a binary verdict with a reason before attempting a graded score. Even agreement on compliant versus non-compliant is difficult to learn. A one-to-five scale adds distinctions that human annotators may struggle to apply consistently, making the target harder to define as well as harder to optimize.

8:108:25
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

8:10 · section reference included

The explanation supplies the missing policy knowledge

In an annotation queue, the reviewer receives a named criterion such as policy adherence and supplies a verdict plus supporting reasoning. The reason is essential training information. A non-compliant label alone tells the optimizer that its answer was wrong; explaining that the agent approved cancellation before checking eligibility tells it which rule is missing. Some narrow tool failures may be evident from the trace itself, but reconstructing a complex business policy from unexplained binary labels is much harder.

Metric design and annotation receive less screen time than optimization, but Mabrouk identifies them as the hardest parts. The data must cover the relevant cases, and its annotations must contain enough information to learn a useful decision rule. This exercise has a small, unevenly distributed collection and a complex target policy. Its explanations are AI-generated from assertions and the original data, rather than collected from human reviewers. The companion extraction code identifies τ²-bench simulation inputs and policy-related assertion tags: the resulting task is derived policy-adherence classification, distinct from the original benchmark’s agent-success score. The recommended human-calibration workflow and the demonstration’s generated reference labels should therefore remain separate.

11:4612:08
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

11:46 · section reference included

The evaluator is the optimizer’s feedback channel

Mabrouk names DSPy as a prominent implementation of prompt optimization, then uses the GEPA authors’ library through optimize_anything. Its candidate is the configuration being optimized: a prompt string, a dictionary containing a prompt and temperature, or potentially a chain of prompts. The interface can therefore search over more than the wording of a single instruction.

The evaluator executes the system configured by that candidate. For this task, it runs the judge, compares its verdict with the reference annotation, and supplies diagnostic information for reflection. A scalar score tells GEPA which candidate did better; the trajectory, verdict, reasoning and annotation help explain how to improve it. Configuration controls the search budget and other behavior, while an objective supplies context for refinement.

The feedback boundary can be expressed in Python without tying it to a particular GEPA release. In this example, run_judge receives the candidate rubric and trajectory; the reference label and explanation are added afterward for the optimizer’s reflection. The function returns both an agreement score and the evidence needed to revise the rubric.

python

from collections.abc import Callable
from typing import Literal, TypedDict

Verdict = Literal["compliant", "non-compliant"]

class Example(TypedDict):
    trajectory: str
    verdict: Verdict
    annotation: str

class Judgment(TypedDict):
    verdict: Verdict
    reasoning: str


def evaluate_candidate(
    candidate: str,
    example: Example,
    run_judge: Callable[[str, str], Judgment],
) -> tuple[float, dict[str, object]]:
    judgment = run_judge(candidate, example["trajectory"])
    score = float(judgment["verdict"] == example["verdict"])
    feedback = {
        "trajectory": example["trajectory"],
        "judge_verdict": judgment["verdict"],
        "judge_reasoning": judgment["reasoning"],
        "reference_verdict": example["verdict"],
        "reference_reasoning": example["annotation"],
    }
    return score, feedback

The recording uses its workshop wrapper around optimize_anything; current GEPA documentation confirms the same candidate/evaluator/diagnostic-feedback pattern, but is not a pinned version of that historical interface.

19:4420:09
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

19:44 · section reference included

Keep related tasks out of the validation split

The notebook uses dotenv, LiteLLM and GEPA, with some helper functions extracted into separate files. Optimization has already run before the recording, so the walkthrough inspects its outputs rather than waiting for another run. Mabrouk’s runtime estimates range from roughly an hour to a couple of hours across the walkthrough.

After loading the processed annotations, the notebook separates optimization data from final validation by benchmark task. The notebook shows 480 training traces and 112 validation traces. The saved optimization summary confirms those split sizes; together they total 592, leaving the earlier stated collection size of 599 unexplained. Repeated runs of the same task and model create redundancy within the data, but Mabrouk says that redundancy does not cross the training/validation boundary. This separation matters because another run of a familiar task would be a weaker test of generalization than an unseen task.

Notebook section “Load and inspect the data” showing dataset-loading code and output reporting 480 training traces and 112 validation traces, with compliant and non-compliant counts.
Loaded training and validation datasets with trace counts.

The annotation examples make the learning target concrete. A compliant trajectory correctly identifies a basic-economy reservation; a non-compliant one fails to recognize that a customer has regular membership. Those details carry the policy knowledge. Without an explanation of why each case is correct or incorrect, the optimizer would have to infer both the hidden business rules and how to apply them from verdicts alone.

22:2622:39
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

22:26 · section reference included

Start with a judge that does not invent violations

The initial rubric is deliberately simple: evaluate whether the agent violated policy, assume compliance, and change the verdict only when a specific reason supports non-compliance. This is an engineered starting point. Earlier prompts that simply asked the model to judge policy violations encouraged it to substitute its own assumptions for rules it had never been given. Mabrouk found those nearly random starting judgments difficult to improve.

Mabrouk reports 61% validation accuracy for the seed judge, with very low recall for non-compliant cases. Its strong tendency toward compliance is intentional at this stage: the seed has little policy knowledge, so it should not manufacture reasons to fail a trace. Inspecting false-compliant cases then reveals the rules that the rubric needs to acquire. Seed sensitivity was consequential for this complex policy task, rather than proof that every judge should use the same default.

26:0626:22
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

26:06 · section reference included

Teach reflection to extract rules from failures

The next intervention changes the prompt that proposes better judge prompts. GEPA’s default reflection template did not produce the improvements Mabrouk expected, so he supplied a custom template with airline-domain context and an explicit instruction to learn policy criteria. Reflection sees the judge’s verdict alongside the reference annotation, then uses that discrepancy to decide what the rubric lacks.

The allowed edits are concrete: add rules, restructure existing rules, and reword instructions for clarity. For the cancellation failure, the useful change is a criterion about verifying eligibility before approval, rather than a general instruction to be more careful. The template directs the refiner toward reusable policy rules. Mabrouk reports that this domain prior helped, despite only limited iteration on the reflection template itself.

Notebook section “Optimize the judge with GEPA” listing six optimization steps and explaining that annotations identify missing policy rules, above the beginning of a reflection template.
GEPA's optimization loop uses annotated failures to improve the rubric.

The experiment’s optimization wrapper constructs configuration from keyword arguments and calls optimize_anything. Its evaluator runs the candidate judge and supplies the trajectory and annotation as feedback. The resulting rubric acquires criteria for flight cancellations and refunds, flight modifications, and communication. The prompt has moved from a default assumption about compliance toward explicit instructions grounded in the annotated cases.

28:5629:09
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

29:09 · section reference included

Better accuracy does not mean the merge problem is solved

For the recorded experiment, Mabrouk reports validation accuracy rising from 61% to 74%. The rounded endpoints imply a gain of 13 percentage points. Non-compliant precision and recall also improve from near zero, indicating that the optimized rubric has learned to flag violations rather than simply passing almost everything.

Mabrouk also reports a compliance-related figure falling from 98% to 64%, but describes it inconsistently as bias, prediction frequency and recall. It should not be treated as a precisely defined metric. The companion repository currently reports different accuracy results, 65.2% to 69.6%; those checked-in artifacts have not been tied to the exact recorded run, so they do not replace the recording’s figures.

Training accuracy reportedly improves by nine percentage points. More strikingly, Mabrouk reports 100% training-task coverage across the Pareto candidate set: for every task, at least one generated candidate gets it right. That is a property of the collection, not the accuracy of the selected judge.

ResultWhat it establishes
Better single-rubric accuracyOne judge makes more correct decisions
Complete candidate-set coverageSome candidate succeeds on each training task
Successful consolidationOne rubric preserves those complementary strengths

The experiment achieves the second property without fully achieving the third. GEPA struggles to merge all the useful information into one prompt, leaving the final judge substantially short of the strong agreement Mabrouk wanted. Imperfect data and limited tuning constrain the result, and reaching it required several unsuccessful experiments.

32:4632:57
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

32:46 · section reference included

Inspect one iteration before paying for a large search

The retrospective begins with model capacity. Using GPT-4o for both judging and refinement failed in Mabrouk’s trials on this complex airline-policy logic. He also tried models described as Mini and Nano, along with Gemini and DeepSeek. His best reported combination used Gemini for reflection and Grok for judging; he also says a model he calls GPT-4 Mini worked fairly well in both roles. The companion Grok/Gemini experiment specifies Grok 4.1 Fast and Gemini 3 Flash Preview, clarifying that saved configuration without resolving all the model names in the spoken comparison.

The useful debugging unit is a small iteration, not a full search budget:

  1. Run a short optimization and inspect the reflection reasoning.
  2. Read the generated candidates and check which ones actually improve.
  3. Stop at a failed example and identify what the refinement prompt misunderstood.
  4. Add the missing context or prior, then test whether the next candidate fixes the training case.

Mabrouk stopped after the first iteration and used Claude Code to edit the refinement prompt. His immediate goal was to make the process fit the training examples before scaling it. That separates an optimizer that cannot learn the available signal from one that can learn but may not generalize. The strong collective frontier coverage then directs attention toward candidate merging as an additional unresolved problem.

Slide titled “How the sausage is made” recommending smart models, inspecting reasoning traces and new candidates, understanding failure modes, and first overfitting to training data.
Inspect failures and candidate improvements before scaling optimization.
34:5135:04
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

34:51 · section reference included

Supplying the policy and learning the policy are different starting points

Mabrouk tested two seed families. One omitted the agent’s original policy; the other copied that policy directly into the judge prompt. The policy-free seed performed better in his experiments. His hypothesis is that the copied policy constrained the search around a difficult local optimum, while a simpler seed left more room to explore alternative rubric structures.

The better-performing seed was not learning without policy information. Its annotations still explained why trajectories complied or failed, carrying much of the policy into the reflection loop. The distinction is where the knowledge enters: as a large starting instruction, or incrementally through evidence about specific decisions. That makes this a finding about initialization and feedback in these experiments, rather than a reason to withhold necessary business rules from evaluators generally.

37:0437:25
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

37:04 · section reference included

Spend the optimization budget where it can reduce recurring cost

Mabrouk estimates that his small experiments cost about $200–$300 in model tokens. Long trajectories make every evaluation input expensive, and capable judge and reflection models add to that cost. He stopped an experiment with GPT-4 because of expense; even the model he calls GPT-4 mini incurred meaningful spending. Moving to cheaper Nano or other smaller models did not produce adequate results in those trials.

The economic motivation for a larger refiner and a smaller judge remains compelling when the judge will evaluate many production traces. Refinement is an upfront search expense; judging becomes a recurring inference expense. Spending more to discover a rubric that a less expensive model can apply reliably may pay off over a large volume of online evaluations. The capability requirement still has to be demonstrated on the application’s actual cases.

Before increasing sampling, instrument the optimization and inspect its traces, generated prompts and training behavior. Mabrouk used Agenta for that inspection and estimates roughly 200–300 iterations per experiment. Batch size and other search parameters also needed tuning. The practical stopping point for the first small run is evidence that reflection can turn a diagnosed failure into a useful candidate; only then does a larger budget have a clear job to do.

38:1638:38
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

38:16 · section reference included

Resources

From the talk

Read the complete timestamped transcript
  1. 0:00

    Hello everyone, and welcome to my talk/workshop, Judge the Judge. And today we're gonna talk about LLM-as-a-Judge. Quite sure you know this scenario. You have an agent in production and someone from the team says, "We need to monitor the reliability."

  2. 0:16

    So you go to one of the libraries and maybe use the hallucination LLM-as-a-Judge. You put it in production within your observability platform and things look fine. But customers are actually saying that the agent is not working, and you look at the traces, it's not working.

  3. 0:35

    You look now under the hood about this hallucination LLM-as-a-Judge, and you'll find a prompt not very far from this one. You'll be given an LLM output, rate whether it's an hallucination, make no mistakes.

  4. 0:47

    Now obviously, how the hell would the agent know whether it's a hallucination? If it could, then your app would have worked from the day one.

  5. 0:55

    So today we're gonna talk about how can we build calibrated LLM-as-a-Judge that works. Calibrated mean calibrated with human annotation, and the way we're gonna calibrate them is by using optimization or prompt optimization.

  6. 1:10

    Specifically, we're gonna use GEPA, um, quite good algorithm for optimizing prompts.

  7. 1:18

    Now why do we want this? Why do we want calibrated LLM-as-a-Judges or good LLM-as-a-Judges? First thing is for our fl-- our offline evaluations. As you know, like usually to create, uh, a good agent or a good prompt, the way you do is you try to experiment with a prompt, then run your evals, see if it improves things

  8. 1:39

    or not. If it does, good. If it does not, you go back and you improve it a little bit, improve the harness, the prompt, and do it again and again.

  9. 1:48

    And the speed in which you move to production or add features is actually the speed into which you can complete this loop. And the bottleneck in this loop is actually the evaluation.

  10. 1:59

    How fast can you evaluate? Obviously, the slowest possible evaluation is having human annotator really look at your whole test set and annotate it manually. Um, the quality is quite good, but then each iteration will take a lot.

  11. 2:15

    Um, you can have faster ones by using an LLM-as-a-Judge, but then if that LLM-as-a-Judge does not, um, uh, correlate with a human annotation, then you'll end up with useless signal.

  12. 2:30

    And although this loop will move fast, it won't go anywhere. So having calibrated LLM-as-a-Judge with a similar quality, let's say, as human annotator will make a development much faster.

  13. 2:43

    The thing-- second thing is basically the online eval, like our example from the beginning. If you have an online eval and you want to see basically in production if things are improving or not improving, same thing.

  14. 2:55

    If you have LLM-as-a-Judges that are calibrated with your business goals, then you can quickly see whether changes that you've made are improving, not improvement, whether, um, there is some change in the distribution of the data, how people are interacting, uh, with, with your agent or model, and basically you react rapidly.

  15. 3:15

    And finally, and I would call this is the holy grail of AI engineering, is really to build this data fl- uh, flywheel, where you optimize your harness, observe some traces, and then add new evals based on these traces, the edge cases, and do it again and again.

  16. 3:32

    And again here, if, if you have a way to kind of add new evaluations quickly, obviously automatic evaluations, um, from the traces, from kind of the annotations, the data, you can go through this loop faster and faster to the moment or to the point that you can think of it as an automatic loop, right?

  17. 3:51

    Because you can optimize the harnesses with optimization techniques like GEPA, which we're gonna use here. But the same thing, you can do it for the evals and basically over time, your application will improve just with, uh, new observations.

  18. 4:05

    So today we're gonna build and optimize these LLM-as-Judges that are calibrated with human annotations. Uh, but before going there, a small intro about myself. My name is Mahmoud. I'm the co-founder and CEO of Agenta.

  19. 4:21

    Uh, Agenta is an open source LLMOps platform, uh, basically providing you all the tools from observability, prompt management, evaluation, covering the whole life cycle of building reliable agents. Um, my experience is in machine learning.

  20. 4:36

    I have more than fifteen years experience in that. Uh, in a previous life, I was in academia, uh, worked on machine learning applied to computational biology, protein structure prediction.

  21. 4:46

    And right now we're working a lot on these sampling and auto optimization workflows. So, uh, if you're interested in that, please reach out. We'd love to have a conversation and show you also what we're building.

  22. 4:59

    So what's the plan for this talk? Basically, we're gonna work on a practical use case. It's a customer support agent that we want to evaluate, and we are going to build an LLM-as-a-Judge that is calibrated with the annotations, basically human annotations for that customer support agent.

  23. 5:17

    The plan would be really to go over the whole process of building this, starting with how we design the metrics, how to think about the data curation, the labeling.

  24. 5:27

    But the main focus would be really about, um, the part about optimizing the LLM-as-a-Judge using GEPA and obviously then validating the results. All the code and the data used in this, uh, will be found in GitHub, and you can find them in the links, uh, in this video and the last slide.

  25. 5:47

    So let's start with the dataset. We're gonna use tau-bench. Tau-bench is a benchmark and a large dataset built by Sierra, a customer support, um, scale-up, I think. And they have like multiple benchmark for real-world scenarios for customer support agents.

  26. 6:08

    Uh, one of them is the airline agent, which we are going to use, um, in this example. And basically what they have is an airline customer support agent that has access to multiple tools to manage reservations, access flight information, access user information, and has a quite complex policy to be held to, like when to change a reservation,

  27. 6:30

    uh, when to provide information, and so on and so forth. Just like a customer support agent, a human one. And the data that we have is, is the agent itself, but most inter-- uh, most importantly, um, five hundred and ninety-nine conversation traces that are generated with annotations.

  28. 6:50

    Uh, now the format, the original format of the annotations is like in the format of assertion, but, uh, I pre-processed or I post-processed the data so that we have for each trace an annotation like a human annotation, uh, where it says, for example, like in this case, you have the conversation that you see here, and then you

  29. 7:09

    have an annotation that the agent is not compliant because it improved-- approved the cancellation without verifying that the reservation met the airline's cancellation rules. So basically the evaluation failed, and the reason is because the agent, uh, um, canceled the reservation without verifying something.

  30. 7:28

    So basically, uh, it did not behold to the policy. And the data is, is more or less, uh, kind of, um, not very skewed. It's sixty-t-two percent compliant, thirty-eight percent compliant, and is generated with multiple models and trials.

  31. 7:46

    Overall, the data is, is kind of-- the problem is quite complex because the policy is quite complex. The data has caveats. Honestly, it's not very clean, um, due to the reasons how it's also generated.

  32. 7:59

    But for our use case, I think it's very, um, interesting use case to test, uh, GEPA and to kind of demo how it would work, uh, in a real, uh, test case.

  33. 8:10

    The workflow that we have is four steps. First thing is designing the metrics. That is deciding what will the LLM-as-a-Judge measure, uh, what are the different axes that it would look to.

  34. 8:25

    The second thing is annotating the data, uh, and then we will optimize the judge and validate the results. Now, the most important thing to take here is that the metrics need to come from, uh, the use case itself.

  35. 8:39

    It does not make sense to have general metrics like hallucination, uh, when you're evaluating your AI agent. It really depends on kind of the business use case. And the best person, the best people to, to, um, to determine these metrics are the subject matter experts.

  36. 8:57

    For example, in the case of a customer support agent, you need, you need to have, um, a subject matter expert look at the conversation, provide the feedback. And I think the, the workflow to do that, the best one that described it is Hamel, uh, from Hamel Dev.

  37. 9:13

    Um, I'm gonna share his, uh, blog and, uh, and the YouTube video. And he really described this idea of error analysis very well, but, but I'm gonna go over it very quickly and also the annotation workflow very quickly.

  38. 9:27

    So the idea is that you, you provide your subject matter expert with all these traces of, uh, the trajectories of the conversation, and they would annotate them first by commenting what did work or what did not work.

  39. 9:44

    But then, uh, kind of slowly trying to cluster, create clusters of the error types, like when it's failing, why is it failing? And, uh, here I'm showing in Agenta how it's done.

  40. 9:58

    And basically here I have like these-- I, I discovered kind of these four error types while going through these, uh, traces. So there is sometimes issues with policy adherence, uh, sometimes issue with the response style, uh, information delivery, basically the agent is not informing the customer that they made a change or something like that.

  41. 10:20

    And finally, some tools has not been colle-- uh, called correctly. And the idea is that we're gonna take these four error types, and then we're gonna build four LLM-as-Judges for these.

  42. 10:34

    So it does not make sense to have one LLM-as-a-Judge, which is success, um, uh, basically try to evaluate all of these. It will make it too complex, and it's very hard to learn.

  43. 10:45

    And you will see a little bit later that even with a simple, like when we're gonna simplify it, it's still hard to learn a calibrated LLM-as-a-Judge or optimize a cali-- a calibrated LLM-as-a-Judge.

  44. 10:57

    So it makes a lot of sense to make things, uh, very specific in these metrics, uh, that we want to evaluate. And the second thing is to move away from one to five scores or like percentages, and instead have like really binary solution, like whether it adhered to policy or not, um, with obviously some reasoning.

  45. 11:21

    Um, and the reason it's, again, it's already quite hard to calibrate an LLM-as-a-Judge with a true/false like bini-binary classification. Uh, adding another layer and saying, "Okay, it should be a number between one and five," it's, it's hard.

  46. 11:34

    It's even hard for human annotator, like to have two human annera-- uh, annotator agree on the same score. So the moment that we have defined these different metrics, uh, start the point of annotation.

  47. 11:46

    Um, here again, I'm using, uh, Agenta. Basically, um, uh, you would take your traces, create an annotation queue, and, and kind of specify for your annotator, like, uh, the name of the, um, the feedback or the evaluator policy adherence here, and then providing like they should provide each one with whether it's adhered to the policy, whether it

  48. 12:08

    does not, and, uh, provide the reasoning. And the reasoning here is very important, uh, because without the reasoning, we will see, uh, the optimization algorithm will need to, by discover itself, like why it failed.

  49. 12:24

    And it's gonna be very hard, like in, u-unless It's a very specific, uh, kind of feedback, for example, tool, um, failure where it can infer things. It's very hard to see, for example, from a conversation why it did not adhere to policy without someone providing information in the beginning about it.

  50. 12:45

    So having that reasoning is very important later for the LLM-as-a-Judge to learn. And again, this reasoning, uh, as I've shown previously with the annotation, uh, it, it kind of describe why, for example, the agent here is non-compliant.

  51. 13:01

    Uh, because, uh, it approved the cancellation without-- before verifying, um, that the reservation met the cancellation rules. So now that we have, so now that we have the annotations, we can go to the optimization.

  52. 13:17

    But before going there, uh, I want to add a small note. Although we went very quickly through the first step and the second step, these are actually the hardest part of the problem.

  53. 13:28

    Like in reality, uh, as every data scientist know, getting your data, um, is the hardest thing. And you need to make sure to look at the data, look at the annotation, make sure that the distribution is, is good, uh, that, uh, the annotation and the information within the data is enough for the algorithm to

  54. 13:53

    learn a representation of the LLM-as-a-Judge that is meaningful. Uh, in our case here, the data is not that good. Uh, the number of traces is small. The problem is quite complex.

  55. 14:06

    Uh, they're not very well distributed because of the reason they have been generated. Uh, also the annotation is actually, uh, kind of AI generated based on the as-assertion and the original data.

  56. 14:18

    You can see a little bit more how it's done in, um, i-in the repository. Um, so it makes things, uh, quite complex for this problem. Um, but it's still quite a good demonstration of how it would, uh, work.

  57. 14:32

    So now that we have the annotated data, we can start with the optimization. And for the optimization, we are going to use the GEPA algorithm. So I'm gonna explain in the beginning how the GEPA algorithm works, and then we can jump to the Jupyter Notebook and start optimizing based on the annotated data.

  58. 14:49

    It's very important to understand how the algorithm works because you will see that practically you need to play around a little bit with the parameters and to get it to work.

  59. 14:59

    And it's very hard obviously to play around with the parameters if you don't understand what do they do. Uh, the algorithm is, um, similar to genetic, uh, algorithm. So basically, the idea is that you start with the seed prompt, and then at each iteration, you try to sample new prompts, see which one works, and then, uh, basically

  60. 15:20

    select the new ones and, and kinda improve over time. Uh, that's kind of the general shape of, uh, the algorithm, and we're gonna go, uh, and look at each step.

  61. 15:30

    So it's three steps. Basically, you sample new candidate each times, evaluate them, see which one go-- work well, and then do some filtering using this kind of Pareto frontier I'm gonna talk about, and then do it again and again.

  62. 15:45

    So let's see how it works. So the way, uh, it works is first you start with a seed candidate. Here in our case, we're gonna use kind of a, a very simple LLM-as-a-Judge, like ev-evaluate whether this customer service agent violated policy, and start with assuming is the agent is compliant.

  63. 16:04

    And now in each iteration, we are going to sample new candidates from the filtered candidates from the last iteration. Now here in the first one, we have only one seed candidate, but in, in the next iteration, we will have a larger bag of candidates.

  64. 16:21

    So GEPA has two strategies to sample new candidates. Uh, one is prompt mutation, and the other one is merging multiple candidates. For prompt mutation, which is what we're gonna u-use in the beginning since we have only one candidate, the idea is that you would run the first LLM-as-a-Judge here, um, with the, the trajectory, and,

  65. 16:46

    uh, if it fails, uh, it-- like this LLM-as-a-Judge will reflect and propose a new prompt. Basically, there'll be some kind of reflection, which means basically we're using the intelligence of the LLM to try to improve the prompt because it looks at the input, looks at the outputs, looks at the results, and try to infer how to make

  66. 17:08

    it better. The other strategy is the merge strategy, which we're gonna use in the next iteration. And basically here it takes two prompts and then kind of put them together.

  67. 17:18

    And if you think about it with an LLM-as-a-Judge, usually you, you have like these guidelines and basically probably what it's gonna try to do is to take guidelines from prompt A, prompt B, and put them together.

  68. 17:30

    So now after we generated a lot of samples, uh, we need to select which one are good. And basically, the way it works is that it would evaluate these new prompts against mini batches of the eval, so not everything.

  69. 17:45

    Um, and if they improve the performance, uh, compared to the starting point, uh, then we select them.

  70. 17:54

    And, uh, they will be added to our bag of prompts, and then starts the next iteration, which is the other, uh, innovation of this algorithm, which is the idea of the Pareto fr-frontier.

  71. 18:11

    Basically, the way we select which prompts or which candidates we're gonna use as a seed for the new iteration is not that we select the ones that have the average best score, like that would be the trivial, um,

  72. 18:25

    uh, solution, right? Look at my, my prompt, see which one Work most by looking at the average over everything and then select these. Uh, instead, what they do is that they, um, try to add diversity by trying to look at what are the best candidate per task, right?

  73. 18:45

    You have like a set of kind of tasks in your evaluation, like in our case, set of trajectories. And you look for each of these trajectory, which is the best candidate, and that is kind of the Pareto frontier.

  74. 18:59

    Um, and then you try to select from these. And basically what you do is you try to select a set at the end of the day that covers your whole test case.

  75. 19:10

    So basically for, for each test case, there is at least one candidate that solves it. And obviously, you see there that, uh, the idea is that you get like a good Pareto frontier, and then you start merging things, and at the end of the day, you have this prompt that solves everything in your training.

  76. 19:26

    Now that you have like this filtered set of candidate, again, we sample new candidates from these, uh, these ones using, uh, kind of the mutation and the merge strategy, and we keep doing this, um, until basically the compute, uh, budget, uh, finishes.

  77. 19:44

    Now, there is a lot of libraries that implement this algorithm. I think the most known is DESPI. It popularized the idea of optimizing prompts or harnesses. Uh, but now there's, uh, I think a new library by the authors of GEPA, an open source one called GEPA, and they have implemented, uh, in the last month, a new interface

  78. 20:09

    called Optimize Anything, a new, uh, API, which is what we're gonna use, and which can be used not only to optimize prompts, but really to optimize, um, any-- almost any algorithm using the same idea.

  79. 20:23

    And it's quite powerful. Uh, let me show you how it works. So basically, uh, the API here is called optimize_anything. You see this function, and what it takes is a seed candidate.

  80. 20:34

    The candidate is the configuration that you want to optimize. In our case, that would be the LLM-as-a-Judge prompt, right? Uh, we can make it even a dict if we want.

  81. 20:44

    So it's kind of, for example, the LLM-as-a-Judge, uh, prompt plus temperature, let's say so. Or it could be chain of prompt and so on or so forth. So it's not limited.

  82. 20:55

    Then we have, uh, the evaluator, which is basically the thing that would be used by GEPA to optimize. And the expectation from the evaluator is that, um, it would obviously run the system.

  83. 21:09

    In our case, it would run the LLM-as-a-Judge, uh, parameterized by the candidate. Uh, and then it would, uh, log, uh, kind of a diagnostic, not only the output, uh, but also the error of the reasoning.

  84. 21:27

    And, and the idea, you can add as much as you want, and you see-- you'll see this is how we're gonna do it with, with our optimization for the LLM-as-a-Judge.

  85. 21:36

    Uh, but the idea is that, uh, if you remember here, we used some kind of, uh, reflection and, and, uh, um, reasoning to improve our prompt, and that reasoning is something that we ourself will build, uh, through this evaluate.

  86. 21:54

    And then other than that, there is ways in the configuration, for example, uh, to configure how many calls to do per iteration. Um, the objective, basically providing context for, uh, the refinement prompt on how to, uh, improve, uh, and so on and so forth.

  87. 22:12

    But, but the, um, the core, uh, flow is actually quite simple. So now let's jump to the Jupyter Notebook and really look into how to do it, uh, step by step.

  88. 22:26

    So you'll find this Jupyter Notebook in the GitHub repository that you'll find in the links and in the last slide. So we start by, uh, installing the library. So it's .env_flight_llm and, uh, uh, GEPA.

  89. 22:39

    I'm not installing here GEPA because I did the optimization. It takes, uh, kind of quite a time, I think a couple of hours, uh, before. So I'm gonna jump this step.

  90. 22:50

    Um, but obviously, if you want to run it within the reposi-- within the Jupyter Notebook, you should also install it. So we install this, and we kind of do our imports.

  91. 23:00

    We have kind of a couple of, um, of functions that, that I extracted outside. We're gonna look at them later.

  92. 23:08

    And we start by loading the data. Uh, as I mentioned, so we're using the data from tau-bench. Uh, I just kind of, uh, pre-process- processed it in the beginning to change the type of the assertion so that they look like the annotation I showed in the presentation.

  93. 23:25

    So I've already kind of split, uh, the data into training and a validation, um, uh, datasets. Uh, so one which we'll use with the GEPA and the other one, the second one, to validate the result at the end.

  94. 23:40

    And the way that I did the split is, uh, based on different tasks that are created in, um, uh, in the tau-bench. And if we look here, basically we have a, a training set with four hundred and eighty traces, uh, with, with around two third, uh, that are compliant, and a validation set with one hundred and twelve

  95. 24:01

    traces that are compliant. As I mentioned, the data here is not, not very, very nice because, uh, there are some redundancies, so there are sometimes the same task, uh, that is, um, being run with, with the same model multiple times.

  96. 24:16

    So there is a little bit of redundancies, but there are no redundancies between the training and the validation set. So we look here how the annotation, uh, looks like.

  97. 24:25

    And again, uh, basically we have an example of a compliant annotation or a non-compliant annotation. Basically a trajectory that, uh, that kind of adheres to the policy. That's the LLM-as-a-Judge that we want to learn, another one that does not.

  98. 24:40

    And we can see here, basically it describes like, okay, it's compliant because, uh, it correctly identified, uh, the basic economy reservation, while here it did not identify, uh, the user membershi- membership as regular.

  99. 24:57

    And, and this annotation is actually quite important for us, for the LLM-as-a-Judge to learn, uh, the policy. Especially in the case here, um, this policy adherence, it's kind of a very complex system, uh, that the LLM-as-a-Judge need to, uh, to learn.

  100. 25:13

    And without kind of information about, uh, what is compliant, like why is something, uh, correct or not correct, it would be, uh, quite impossible for the, uh, GEPA algorithm to, to reach, uh, a good LLM-as-a-Judge, right?

  101. 25:32

    I mean, it would be the same for a human, right? If you gave me all these trajectories, told me this is, uh, kind of correct, this is non-conformed to policy, but you did not give me, uh, more information, it would be very hard for me to, um, to basically make a judgment, learn how to assess the policies.

  102. 25:50

    So having this information and the quality of the annotation, as I mentioned, the quality of the data is really paramount of being able to learn this. Uh, and again, obviously this is kind of bit of a complex, um, LLM-as-a-Judge to learn.

  103. 26:06

    So, uh, first thing we start is, is with a naive, uh, judge and, uh, basically this is the seed judge, uh, we start with. Um, and, and it's, it's something that, that actually I engineer, engineered.

  104. 26:22

    I'm gonna, uh, talk a little bit about it later with the learnings on like how exactly did we reach this. And basically you can see here is like it evaluates whether the customer service agent violated policy, and it tells that you should start by assuming that the agent is compliant and, uh, only change to non-compliant if there

  105. 26:45

    is a specific reason, right? I mean, here we, we are starting with an LLM-as-a-Judge, which means that, um, like the seed judge, the initial judge should actually, uh, in my opinion, start by, by saying everything's all right, right?

  106. 27:00

    I mean, if I don't have any rules, uh, it should say everything is all right. I started in, uh, like in another example, when I started as I created an LLM as a judge that says, "Okay, you should check whether the agent violated policy."

  107. 27:13

    And what you end up being is basically the LLM with its own biases trying to make that decision by itself. Says, "Okay, this is violates, this doesn't violate," without having any information.

  108. 27:24

    So without telling it in the beginning that you should start assuming that it's compliant. I mean, if you don't have any reason to, to believe it's non-compliant, it should be compliant.

  109. 27:35

    Um, then, uh, basically you start with, with some kind of random, uh, LLM-as-a-Judge that would be very hard to fix later, uh, unless you end up with one prompt that discovered this thing, right?

  110. 27:50

    That it start with a compliant. So the, uh, I discovered here that the initial seed is actually very important, uh, in this case. There might be simpler scenarios where you don't need this, but in this case it's kind of, uh, quite important.

  111. 28:02

    So if we take this and we run this on the validation set, like this, uh, initial, uh, LLM-as-a-Judge, uh, we basically find sixty-one percent accuracy, but, but we look like the bias, it's actually most of the time saying it's compliant, which is actually what we want, right?

  112. 28:18

    I mean, if that's, I would say saying it's compliant ninety-eight percent of the time is actually the unbiased thing to do, uh, the logical place where to start. Um,

  113. 28:31

    so, uh, we run the metrics in the beginning, right? The accuracy sixty-one percent, ninety-eight percent is saying like the recall of, of compliance with very low to recall for non-compliance.

  114. 28:44

    Um, and I think as I mentioned, this is quite all right. It's biased towards compliance, and I've had experiments in the beginning where it was kind of almost random, but then it doesn't learn at all.

  115. 28:56

    And we can look into why or where it goes wrong and, uh, basically by looking at the places where it does, does work and we see like it says compliant, but it's not compliant because it doesn't know the policy, right?

  116. 29:09

    So we start here like the main code of kind of optimizing the judge with GEPA. And what you will see is that I have actually, um, wrote, um, a reflection template.

  117. 29:23

    So that prompt that GEPA uses to reflect and to improve, uh, or to sample new candidates, I did not use their default, but actually I wrote one. Uh, I tried in the beginning by using the default prompt in, in, um, in, uh, in GEPA, but the results were not, uh, as good as I expected.

  118. 29:44

    It was very hard for it to, uh, to learn. And what I tried to do is, is to provide, um, basically a bias and prior within the re-reflection, uh, template.

  119. 29:58

    So you see here, for example, I mentioned obviously that, uh, it's basically, uh, the judge is reading an airline customer service, um, and it needs to kind of decide which is the basics.

  120. 30:10

    But then you can look at, um, more information, for example, uh, that our annotation that the, this, uh, kind of reflection template sees includes also, uh, the judge verdict, the ground truth, like the annotation.

  121. 30:24

    Like this is an important information that the reflection template should look into and improve. Um, and uh, basically I explain to, to, to the LLM how to do this.

  122. 30:37

    You can add rules, restructure existing one, uh, reward things for clarity, um, and, and try to think about it that The, um, the reflection template should basically create a real policy rules, right?

  123. 30:52

    Uh, it should find the right policies and abilities. And I think adding that, uh, was very, um, important to kind of improve the quality. Uh, otherwise, the default reflection template did not understand, uh, that, that it should kind of try to, uh, learn the, the policy more or less, right?

  124. 31:14

    With the LLM-as-a-Judge, uh, to some degree. Um, so that's the second thing, uh, kind of I changed, and I mean, honestly, I iterated only a little bit on it.

  125. 31:24

    And then we run the optimization. Run optimization is basically a wrapper around, uh, optimize_anything, and it just, uh, uh, kind of, uh, parameterize it since I ran like multiple experiments, uh, to find the one, and it's actually, uh, it will be part of the GitHub repository, and it's actually something that you can play around with and start

  126. 31:46

    with when you're exploring, uh, the space of design, uh, in GEPA. And you can see here, it basically tries, um, to build, um, the configuration based on the parameters like the, the quarks, and then calls optimize_anything, uh, with these.

  127. 32:01

    And for the, uh, kind of, um, uh, the make evaluator, it's basically, uh, it calls the LLM-as-a-Judge and all-- adds all the side information. So it doesn't only provide the trajectory, but also kind of the annotation, which is quite important.

  128. 32:16

    Um, and then we run this. Uh, as I mentioned, it takes around an hour to run. Um, and you can see here the, uh, the basically, uh, the results.

  129. 32:27

    This is the optimized, uh, rubric, and you can see compared to the default where we started, it's, it learned part of the policy criteria, like the flight cancellation and refines, uh, flight modification, um, uh, how to communicate, and so on and so forth.

  130. 32:46

    Now, if we look at the results, like with the kind of evaluate, uh, rubric to evaluate it, we see that the accuracy increased from sixty-nine percent to seventy-four percent.

  131. 32:57

    And, uh, we removed the bias, right? So what especially changed is the recall for the non-compliant and the precision for the non-compliant, which was basically zero in the beginning.

  132. 33:08

    Now, uh, the LLM-as-a-Judge is, uh, has less bias at sixty-four percent, so previously it was ninety-eight percent, and it's really learned parts of the policy. So looking at the results, as I mentioned, like for the validation set, we had, uh, quite a lot of improvement, like fourteen percent.

  133. 33:27

    And, uh, for the training accuracy, it improved by nine points. And we can see that the Pareto frontier, interestingly, accuracy is now a hundred percent, meaning that for each task, there is one candidate that we generated that solved it.

  134. 33:42

    Uh, the issue the algorithm faced is how to merge all these candidates and all the information to have one prompt that solves everything. Um, and it struggled to do this.

  135. 33:52

    So at the end of the day, we improved the LLM-as-a-Judge, we improved its accuracy, but it's very still quite far from kind of ninety-five percent accuracy or something that is really well aligned with the human judgment.

  136. 34:06

    Obviously, here I didn't invest extreme amount of time in it, and as I mentioned at the beginning, the quality of the data is also, um, would be better, I would guess, uh, in other cases.

  137. 34:18

    It's really a tricky, uh, example. Um, but, but nevertheless, it took actually quite a number of iteration, I think that's the biggest learning to, uh, to reach this LLM-as-a-Judge.

  138. 34:31

    It's not an algorithm that you just take and it works from, from day one, unless for kind of, uh, toy examples. And, uh, I wanted to show a little bit in the end, like what are the experiments I, I tried in the beginning, uh, that failed, and how did I think about fixing them.

  139. 34:51

    Um, the first thing was actually, uh, using a smaller or older model, like using, uh, GPT 4.0, uh, for both the refiner and the LLM-as-a-Judge. And that was a complete failure.

  140. 35:04

    Like, uh, smaller models really are very bad, at least in this example, to be either an LLM-as-a-Judge or a refiner. Um, uh, for the LLM-as-a-Judge, providing all this policy especially, it has a lot of kind of complicated logic.

  141. 35:21

    It just failed and could not improve it. Uh, I tried other models. I tried Mini and, uh, Nano and Gemini and DeepSeek and, and you see that the best kind of results with this kind of, uh, using, uh, Gemini for reflection and, uh, Grok for a judge.

  142. 35:37

    But I would say also using, uh, GPT-4 Mini for both is actually quite good, and the results quite well. The other thing was actually trying how to try to debug it.

  143. 35:49

    And, and what I tried to do from the beginning is really to not start sampling, doing big experiments from the beginning, but trying first, uh, kind of a small iterations, looking at the reasoning LLM, looking at the candidate, how do they improve, how many improved, and understanding what's happening.

  144. 36:10

    And that actually what, uh, uh, what allowed me to kind of think about improving the refined prompt, um, and, and basically adding some, uh, prior there to, to kind of help solve it.

  145. 36:24

    Basically, what I did is I stopped at the first iteration, found some example, and then looked a little bit, kind of fine-tuned, um, in Claude Code, uh, that refinement prompt to, uh, to basically allow it to improve, um, uh, the candidate.

  146. 36:41

    And, and as always in machine learning, like what you always try to do is to overfit for the training data. Not trying to run the whole algorithm, but really trying to find a way so that it works.

  147. 36:51

    And I think what we saw with the Pareto frontier reaching one hundred percent is we almost overfit to the training data. But obviously for the merge, there are like things I think we can do to improve.

  148. 37:04

    And the final thing was kind of this iteration on the seed prompt. There I actually, um, iterated on multiple seed prompts, and there were two families. One which, as you have seen here is, uh, uh, kind of was not-- did not include any information about the agent prompt because we have access to that, right?

  149. 37:25

    And the agent prompt does have access to the policy, and one which had access to the policy. So basically, it was this prompt that I've shown, uh, but then the policy of the agent, like really copy-pasted.

  150. 37:38

    And interestingly, uh, the, uh, prompt that did not have access to the policy did, uh, better because, um, my hypothesis is that if you have access to the agent policy from the beginning, then it's very hard to fine-tune it.

  151. 37:54

    You're already stuck in the local minima that you can not improve on. But if you don't have access to the policy and, uh, yet obviously you have access to the annotations that describe, in this case, all the policy, uh, or a large part of the policy, then you, you are able a little bit, uh,

  152. 38:16

    to, um, to explore the space of the prompts much better. Um, and finally, the last point is beware of the cost. I mean, um, even these small experiments I've done, I think they cost like two, three hundred dollars, uh, in tokens, especially since, uh, the trajectories are long, so there is a lot of input tokens, uh, in

  153. 38:38

    this case. Uh, but, um, the models that are used, um, are actually quite expensive, right? Uh, GPT-4, I mean, I tried a little bit to play around with GPT-4, but that ate a lot of money, so I stopped the experiment.

  154. 38:55

    But even GPT-4 mini is quite expensive to some degree. And then if you go, uh, nano, at least from what I've seen, it doesn't work right also. You, you go to kind of smaller model, cheaper model, it does not work.

  155. 39:09

    Usually, what they say you should use, uh, kind of a bigger model for the refinement prompt and smaller model, uh, for the LLM-as-a-Judge. I think it makes sense, especially if you're running LLM-as-a-Judge, uh, against a lot of traces, like in the case of online evaluation.

  156. 39:23

    It's obvious that it's, it's worthwhile the investment of spending money on the optimization to lower the cost on the long term. And I think there is a lot of use cases where it worked.

  157. 39:36

    So again, first, uh, overfit to the training data, start with a small iteration, uh, visualize. So basically, instrument the traces. I instrumented them using Agenta in this case. Uh, try to look at them, try to look at the prompts that have been generated, and understand how the algorithm is working before, uh, increasing the sampling.

  158. 39:57

    And in this case, I think we had, uh, around two hundred, three hundred iterations per experiment. Um, in addition to that, there is actually a number of parameters like the batch size and so on that you need to, uh, fine-tune to get the algorithm to work.

  159. 40:12

    So that's it. Thanks a lot for watching. I hope that has been helpful and that you'll build good LLM-as-a-Judges that helps you to improve your applications. Uh, I'd love if you check out Agenta, our open source LLMOps, uh, platform.

  160. 40:30

    Um, and you can follow me both on LinkedIn and X. And finally, if you're thinking and working about auto optimization, uh, about how to, uh, optimize prompts, uh, feel free to reach out or to write in the comments on YouTube.

  161. 40:48

    Have a great day. Thank you.