AI Engineer World's Fair 2025
Fuzzing in the GenAI Era
Read the talk
Fuzzing in the GenAI Era
Reliable AI applications need more than a golden dataset: they need guided searches for failures and judges whose measurements can withstand scrutiny.
From a talk by Leonard Tang
Before you start: Familiarity with LLM applications, evaluation datasets, and basic Python will help; no prior fuzz-testing experience is required.
The gap between a demo and production
How do you validate, audit, and steer an application whose outputs are subjective, unstructured text? Leonard Tang approaches that question as a quality assurance problem. Haize’s approach draws on property-based testing and fuzz testing, which he calls Haizing: pressure-test an application through large-scale simulation, optimization, and search before exposing it to production traffic.
The practical gap is familiar: in Tang’s 2025 framing, a weekend project can produce an impressive LLM demo, yet getting that same application to enterprise reliability remains difficult. More than two years after ChatGPT’s launch, the promise of autonomous workflows still runs into questions of trust and risk. A working happy path establishes that an application can succeed; predeployment testing must investigate where that success stops.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Similar inputs, different behavior
A conventional evaluation starts with a subject-matter expert assembling a golden dataset: inputs paired with expected outputs. The application processes those inputs, and an evaluator compares its responses with the reference answers. That measures performance at the selected points. It does not establish how the application behaves between them. Tang describes the problem as brittleness, using “Lipschitz discontinuity” to evoke a large output change following a small input change rather than establishing a formal mathematical property of the application.
This differs from asking whether repeated calls return identical answers. Tang argues that temperature-zero workflows largely constrain that source of variation, while acknowledging residual provider and systems effects. The more consequential problem is sensitivity to input perturbations: two requests can differ slightly in syntax, semantics, or visual appearance and produce radically different behavior. Repeating one request successfully does not test its neighbors.
Tang illustrates the stakes with reports of Air Canada support hallucinations, allegations involving Character.AI’s suicide-related responses to teenagers, and a Chevy chatbot offering a pickup for one dollar. The last example is an offer generated by a chatbot, not evidence of a completed sale. These examples connect input sensitivity to failures that users experience as incorrect advice, unsafe responses, or unauthorized commitments.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Two separate weaknesses in static evals
Coverage is the first weakness. An application could pass every golden example and still fail on a nearby formulation that the dataset omits. Adding examples helps only to the extent that those examples explore the relevant input space. A perfect result on a finite test set is compatible with undiscovered failures just outside it.
Measurement is the second weakness. Even with the right inputs, how should a generated answer be scored? Ideally, a domain expert would continuously inspect the application with the right knowledge, taste, and sensitivity. Automating that inspection requires translating the expert’s criteria into quantitative measures—the difficult problem underlying reward modeling.
The usual choices include exact match, classifiers, LLM judges, and semantic similarity. Each operationalizes a different notion of correctness or quality. The engineering problem therefore has two parts: find revealing inputs, and make sure the measurement recognizes the failures those inputs expose.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Use failures to guide the next test
Haizing turns evaluation into an iterative feedback loop:
- Generate simulated user interactions.
- Send them to the application and collect its responses.
- Judge, analyze, and score those responses.
- Use the scores to guide the next round of input generation.
The distinguishing step is the last one: evaluation results influence where the search goes next.
The following Python function expresses that control flow. propose receives the accumulated observations, while judge supplies a quality score and is_failure applies the chosen failure criterion. The returned history preserves the inputs and outputs needed to inspect a finding.
python
from collections.abc import Callable
from dataclasses import dataclass
@dataclass(frozen=True)
class Observation:
prompt: str
response: str
score: float
def fuzz(
application: Callable[[str], str],
propose: Callable[[tuple[Observation, ...]], str],
judge: Callable[[str, str], float],
is_failure: Callable[[Observation], bool],
budget: int,
) -> tuple[list[Observation], Observation | None]:
history: list[Observation] = []
for _ in range(budget):
prompt = propose(tuple(history))
response = application(prompt)
observation = Observation(
prompt, response, judge(prompt, response)
)
history.append(observation)
if is_failure(observation):
return history, observation
return history, None
Search stops when it finds a failure or exhausts its budget. Tang treats exhausting the budget without a discovered failure as a production-readiness signal; it is a bounded search result, not proof of correctness. Both the proposal function and the judge remain substantial technical problems.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
The judge needs its own quality assurance
The simplest LLM judge receives an application response and a rubric, then assigns a rating—perhaps from one to five or one to ten. This is easy to assemble, but the model doing the evaluation brings its own failure modes.
- Hallucinated judgments: The evaluator can invent reasons to accept or reject an answer.
- Unstable criteria: A clearly written rubric may still fail to produce consistent decisions.
- Uncalibrated scores: A human’s interpretation of a rating can differ from the model’s interpretation.
- Order and context sensitivity: Reversing two candidate responses, changing surrounding context, or modifying the rubric can change the verdict.
A single off-the-shelf model call can therefore make the measurement itself unreliable.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Spend compute on better judgments
Before optimizing an application against a judge, the judge must be credible enough to serve as the target. Tang’s response is judge-time compute: apply the idea of compute scaling to evaluation itself. He describes two ends of a spectrum.
| Approach | Where the structure comes from |
|---|---|
| Train reasoning judges with RL | Learned evaluation behavior, with fewer imposed priors |
| Build agents from existing models | Explicit workflows and strong architectural priors |
Both spend more effort on reaching a judgment, but one changes the model and the other changes the process around it.
Verdict implements the structured approach through judging pipelines and reusable primitives. Its inspiration comes from scalable oversight: how can weaker systems audit, correct, and steer stronger ones? That question originally arose from concerns about humans overseeing superhuman AI, but it also suggests practical ways to organize smaller models around a difficult evaluation task.
- Debate: Weaker models challenge one another’s assessments of a stronger model’s response.
- Self-verification: A judge critiques its own explanation for why a response is good or bad.
- Ensembling: Multiple judgments contribute to the final decision.
These primitives separate an initial verdict from the work needed to check and combine it.
For expert-QA verification—described in the talk as grading subjective criteria in expert domains—Tang reports that Verdict outperforms o1, o3-mini, GPT-4o, and Claude 3.5 Sonnet. He describes a GPT-4o mini backbone arranged as a self-verified debate ensemble. Tang reports less than one-third of o1’s cost and less than one-third of its latency for that comparison. He attributes the efficiency to carefully chosen architectural priors.
The companion whitepaper does not substantiate that exact configuration: its ExpertQA hallucination-detection table places GPT-4o Verdict above o1 and GPT-4o-mini Verdict below o1, and describes a self-verified ensemble rather than explicitly a debate architecture. The spoken mini-backed comparison and its cost and latency claims should therefore remain attributed to Tang, not treated as a reproduced result from the paper. The broader design under discussion is using a structured judging process to make more effective use of smaller models.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Learn a rubric for each instance
The other approach trains models specifically to judge. Tang focuses on two shortcomings of ordinary LLM judges: ratings without coherent rationales, and criteria too generic for the particular task or response. Reinforcement learning, specifically GRPO tuning, is his proposed way to improve both.
DeepSeek’s Self-Principled Critique Tuning, or SPCT, provides the pattern: first generate criteria specific to the data point, then critique the response against those criteria. The criteria resemble unit tests for an individual example. Instead of applying only a fixed global rubric, the judge must identify what matters for this instance and explain whether the response satisfies it.
Haize experimented with a variant of this approach, using GRPO to train 600-million-parameter and 1.7-billion-parameter judges. Tang compares the resulting J1 Micro model with larger models on RewardBench, a pairwise preference evaluation. The talk’s rounded figures are:
| Model | Reported RewardBench accuracy |
|---|---|
| J1 Micro, 1.7B | 80.7% |
| Claude 3 Opus | About 80% |
| GPT-4o mini | About 80% |
| Llama 3 70B | 77% |
These are reward-model preference results, not application reliability rates. Haize’s repository corroborates the comparison and gives the two rounded baselines as 80.10%, identifying them as Claude-3-Opus-20240229 and GPT-4o-mini-2024-07-18.
The intended mechanism is better rubric proposals followed by better instance-specific critiques. Tang also describes the 600M model as achieving similar numbers, but Haize’s public repository reports j1-nano at 62.35%, so the approximately 80% result should not be extended to that smaller model.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Search for inputs that expose failures
A strong judge solves only half the problem. The system still needs inputs worth testing. Tang distinguishes two search regimes:
| Regime | Inputs to explore |
|---|---|
| General fuzzing | Plausible variations on customer happy paths |
| Adversarial testing | Prompt injections, jailbreaks, and deliberate disruption |
The first stays near reasonable, in-distribution use. The second emulates someone actively trying to break the application and pursues the optimization more aggressively.
Natural language makes exhaustive enumeration impractical. Tang invokes Llama 3 and roughly 128,000 token choices to illustrate the scale. That number refers to the tokenizer’s vocabulary, as Meta’s announcement specifies, not the length of each input. Each additional token position multiplies the possible sequences, so search needs guidance and pruning.
The resulting problem is discrete optimization. The search domain is natural language; the objective is to find inputs whose application outputs receive low quality scores from the selected judge. Established optimization methods supply the starting point, but they need adaptation to the LLM setting. A search is only as meaningful as its objective: here, breaking the application means violating the properties that the judge measures.
- Gradient methods: Where model access permits it, backpropagate a judge loss through the model to guide input-token substitutions.
- Tree search and MCTS: Explore candidate branches using tree search, including Monte Carlo tree search.
- Embedding-space search: Search a latent representation, map candidates back to text, and submit that text to the application.
- DSPy: Use optimization tooling such as DSPy with Verdict to help search against a judging objective.
These are alternative ways to select promising candidates without enumerating the entire language space.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Testing a loan assistant against its code of conduct
Regulated applications make the connection between testing and deployment concrete. Tang describes work across banking, financial services, and healthcare, then gives the example of a customer-facing loan-calculation assistant at what he calls Hungary’s largest bank. Its behavioral requirements were expressed in an eighteen-line code of conduct.
Haize used optimization and scoring to emulate adversaries against that assistant. Tang reports finding prompt injections, jailbreaks, and unexpected corner cases that the code of conduct had not anticipated. The findings gave the bank specific behavior to repair; he says those patches unblocked production deployment. The case joins the two halves of the method: policy-aligned judging identifies violations, while adversarial search finds interactions that trigger them.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Voice adds acoustic variation and annotation work
The next case extends the input space beyond text. A Fortune 500 bank was testing outbound debt-collection voice agents. Alongside conversational variation, Haize introduced background noise, static, and frequency changes into the audio. The search remains an optimization problem, but candidates now vary in their acoustic properties as well as their words.
Tang relays the customer’s estimate that roughly three months of internal operations work took five minutes on Haize’s platform for this voice-agent testing task. The comparison does not establish equivalent test scope or a controlled timing protocol, but it explains the customer’s interest in scaling adversary emulation.
A separate voice-agent company used Verdict to expand subjective evaluation capacity rather than to run adversarial search. Tang reports a 38% increase in agreement with human ground truth, describing the comparison as against the customer’s internal operations teams. A related Haize case study describes a prior single GPT-4o judge instead; the baseline is therefore not settled by the available accounts, and neither specifies whether 38% means relative improvement or percentage points.
The architecture is rubric fan-out:
- Propose individual criteria or unit tests for the data point.
- Critique the response against each criterion.
- Self-verify those critiques.
- Aggregate the results into a final judgment.
This separates the evaluation into focused checks before combining them, applying the same judge-time compute idea to the work of subjective annotation.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Testing the conversation, not just one prompt
Tang closes by describing strong enterprise demand, a four-person team, and active hiring in New York. The final audience question returns to the testing boundary: does Haizing operate on single-shot inputs or longer interactions?
His answer is both: single-turn and multi-turn testing, including persistent conversations for voice, across multiple modalities and input types. The unit under test can therefore be an extended interaction, with later inputs arriving in the context created by earlier turns.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Resources
From the talk
Python library for composing judges from reasoning, verification, and aggregation units.
Introduces SPCT for generating adaptive evaluation principles and critiques, with additional inference compute improving reward modeling.
Training and evaluation code for small reward models that generate instance-specific rubrics and critiques.
Model weights, loading instructions, and reported RewardBench results for the 1.7B-parameter judge.
Evaluation tools for testing reward models against preference data.
Further reading
Explains compound judge architectures and reports results on safety moderation, correctness, and hallucination detection.
A voice-agent evaluation case study using judge ensembles and separate checks for each rubric item.
Example of using an ensemble judge as the metric for automatic red-teaming.
Read the transcript and explore slides
Loading transcript and slides…