Safety & evaluation research
Measuring and reducing what could go badly.
Empirical work on what a model does wrong and how badly. In practice it is three activities: building test sets for capabilities that would be dangerous if the model had them, red-teaming — deliberately trying to make a model behave badly and writing down what worked — and studying behaviour under pressure, such as whether a model acts differently when it appears to be under test.
Capabilities ship whether or not anybody has measured their downside, and the measurement does not exist until someone builds it. Without one, "the model will not help with that" is an assertion; with one it is a number that can be watched across releases and argued about with evidence.
It is eval work with a different subject: the same discipline of datasets, graders and held-out sets, pointed at harm rather than at product quality. It sits beside alignment, which is the training side of the same question, and interpretability, which inspects the internals. Claims here are unusually easy to overstate in either direction, which is why the writing standard in this area is high.
The work is building the measurement, not predicting the future.
In more detailBuilding evaluations for dangerous capabilities, red-teaming for failure modes, and studying how models behave under pressure or deception. It combines empirical rigour with unusually careful thinking about what a result actually licenses you to claim.
Learn first
Measuring and reducing what could go wrong
By the end: You can describe safety evaluation work and why it is methodologically hard.
- What the field covers
- Dangerous capability evaluation
- Red teaming
- Why absence of evidence is weak here
Safety work splits into harms happening now — misuse, deception, bias, privacy, generated content that damages people today — and capabilities that would be dangerous if they appeared, which have to be tested for before they do. This section covers how each is evaluated and what red teaming involves. It also covers why the methodology is so hard: a test that finds nothing is weak evidence, because it may only mean nobody asked in the right way.
Two kinds of concern#
- Present harms: misuse, deception, bias, privacy, generated content that damages people now.
- Anticipated harms: capabilities that would be dangerous if they appeared, evaluated before they do.
The failure modes, named#
Most of this field is a small number of named failure modes, each with its own measurement. Learning the names properly is worth more than any general position on whether the technology is dangerous, and it is what an interview is checking. The table is the recognition rule; the definitions follow.
failure mode what you see measured by
specification gaming objective satisfied, intent not inspecting behaviour, not score
reward hacking proxy reward rises, quality falls a held-out human judgement
sycophancy answer follows the user's stated view paired prompts differing in the cue
jailbreak refusal bypassed by a framing attack success rate over many attempts
sandbagging worse when it looks like a test matched prompts, one framed as an eval
unfaithful reasoning stated reasons do not drive the answer intervening on a hidden cueSpecification gaming is the oldest and the most general: the system optimises exactly what you wrote down, and what you wrote down was not what you meant. The standard example is an agent trained to score points in a boat racing game, which found that circling a lagoon hitting respawning targets scored better than finishing the race, and so never finished a race. Simulated robots asked to move forward have learned to grow tall and fall over. The pattern to recognise is that nothing malfunctioned. The objective was maximised, and the objective was wrong.
Reward hacking is specification gaming where the specification is itself a learned model. In preference training, a reward model is fitted to human comparisons and then the policy is optimised against that model. The reward model is an approximation, and optimising hard against an approximation finds the places where it is wrong. The visible symptom is that the reward keeps going up while human raters start preferring the older model.
Sycophancy is the specific case where the reward model learned that raters like being agreed with. The model then shifts its answer towards whatever the user appears to believe, including on questions with a fact of the matter. It is easy to measure and unusually easy to demonstrate, which makes it a common interview question.
A jailbreak is an input that gets the model to do something its training was supposed to prevent. They come in a handful of families, and knowing the families is more useful than knowing any particular prompt, because the prompts are patched and the families are not: role-play and fictional framing, competing instructions that give the model a higher-priority-looking authority, obfuscation such as encoding or translating the request, multi-turn build-up that establishes context gradually rather than asking directly, and automated search for token sequences that happen to work. The last family matters most for evaluation, because it does not need a person to be creative and it transfers between models more often than people expect.
Note what these have in common. None of them is the model breaking. Each one is the model doing well at something adjacent to the thing that was wanted, which is why the fix is rarely a bug fix and usually a change to what is being measured or optimised.
Reward hacking, measured#
The reason reward hacking is hard to catch is that every number on your dashboard improves while it happens. Here is the smallest model of it that shows the shape. One axis, x, stands for how much an answer flatters and pads. True quality is best at a moderate amount and falls away either side. The reward model was fitted on data near x equal to zero, and it picked up a mild preference for x that the humans did not have. Optimise the policy against the reward model and watch both curves.
true_quality = lambda mu: -(mu - 1.0) ** 2 - 1.0 # averaged over answers drawn around mu
proxy_reward = lambda mu: true_quality(mu) + 0.6 * mu
gradient = lambda mu: -2 * (mu - 1.0) + 0.6
mu, lr = 0.0, 0.08
for step in range(41):
if step in (0, 2, 5, 10, 15, 20, 30, 40):
print(step, round(mu, 3), round(proxy_reward(mu), 4), round(true_quality(mu), 4))
mu += lr * gradient(mu) # gradient ascent on the reward model, nothing elsestep x proxy reward true quality
0 0.000 -2.0000 -2.0000
2 0.383 -1.1514 -1.3810
5 0.756 -0.6056 -1.0594
10 1.073 -0.3617 -1.0053 <- true quality peaks here
15 1.205 -0.3190 -1.0420
20 1.260 -0.3116 -1.0677
30 1.293 -0.3100 -1.0859
40 1.299 -0.3100 -1.0893 <- reward is still improvingTwo lessons come straight out of that table. The first is that you cannot detect this from the reward curve, by construction, so a training run optimising a learned reward needs a separate held-out judgement that the reward model was not fitted on, sampled periodically. The second is the reason a KL penalty is in every one of these algorithms: it charges the policy for moving away from the reference model it started from, which keeps it inside the region where the reward model was actually fitted.
for beta in (0.0, 0.2, 0.6, 1.0, 2.0):
settles_at = 2.6 / (2 + beta) # where gradient ascent stops once the penalty is added
print(beta, round(settles_at, 3), round(true_quality(settles_at), 4),
round(proxy_reward(settles_at), 4))
# beta x true quality proxy
# 0.0 1.300 -1.0900 -0.3100 no penalty: fully over-optimised
# 0.2 1.182 -1.0331 -0.3240
# 0.6 1.000 -1.0000 -0.4000 exactly the right answer
# 1.0 0.867 -1.0178 -0.4978
# 2.0 0.650 -1.1225 -0.7325 penalty so heavy the model barely movesThat is the honest state of the technique. The KL coefficient is a knob whose correct value depends on how wrong your reward model is, which is the thing you do not know. In practice it is chosen by sampling the policy at intervals and having people or a separate judge compare against the reference, which is expensive and is the reason these runs are supervised rather than left to finish.
Capability evaluation#
Build tasks that measure whether a model can do something concerning, and measure before deployment rather than after. The methodological difficulty is that a model failing your test may still succeed with better prompting, more scaffolding or more attempts.
Failure to elicit is not absence of capability
This is the central problem in the field. A negative result means you could not elicit the behaviour, not that the model cannot do it. Serious evaluations therefore try hard to elicit, with scaffolding and multiple attempts, and report the effort as part of the result.
Red teaming#
Deliberately attempting to make a model behave badly. Manual red teaming finds creative attacks that automated methods miss; automated red teaming scales and covers more ground. Both are needed, and findings feed back into training and into guardrails.
What makes it hard#
- Absence of evidence is weak evidence, as above.
- Capabilities can appear with scaffolding rather than with scale, so a model evaluated alone may behave differently in an agent.
- Measuring intent or deception is far harder than measuring capability, and interpretability is one of the few routes into it.
- Publishing details of a vulnerability can enable it, so disclosure norms are genuinely contested.
What the training-side methods actually do#
The mitigations have names too, and being vague about what they do is the fastest way to sound unserious. Preference training from human feedback has three steps: collect comparisons where a person picks the better of two model outputs, fit a reward model that predicts those picks, then optimise the policy against that reward model with a KL penalty back to the starting model. Constitutional or AI-feedback methods replace the human in step one with a model asked to judge against a written set of principles, which makes the labels far cheaper and makes the principles inspectable and arguable, since they are written down.
Both do something real: they are why a deployed model answers in a helpful register, declines obvious misuse, and follows instructions at all. Neither does what it is often described as doing, and the gaps are specific.
- The reward model is a proxy, and the section above is what happens when you optimise it too hard. Its quality is also bounded by how much the annotators agreed, which on subtle comparisons is not very much.
- It changes behaviour, not knowledge. Training a model to decline a request does not remove the capability behind it, which is why an elicitation result and a refusal rate are different measurements and why a safety claim based on refusals is weak.
- The trained behaviour is not robust to further training. Fine-tuning an aligned model on a small amount of unrelated or adversarial data can substantially undo the refusal behaviour, which matters a great deal for anyone offering fine-tuning as a product feature.
- Coverage follows the data. Behaviour is shaped where the preference data had examples, so unusual framings, other languages and long multi-turn contexts are systematically weaker, which is exactly where jailbreaks live.
- Agreement is rewarded. A rater's preference for being agreed with is in the data, so sycophancy is not a bug in the method but a faithful reflection of what was optimised.
The practical consequence for an engineer is that training-side alignment is one layer and not a boundary. A deployed system also needs input and output checks it does not control from the same weights, an architecture where secrets are not in the prompt, and a measurement of the attack success rate it actually has rather than the one the model card implies.
The open problems, stated plainly#
Say these as open problems rather than as either crises or curiosities. They are the questions people are paid to work on, and being able to state one precisely is a better interview answer than any opinion about timelines.
- Scalable oversight: how to train or evaluate a model on tasks where a human cannot readily check the answer. Every method above assumes a judge who knows better than the model.
- Evaluation validity: whether a benchmark score corresponds to the real-world behaviour it is named after, especially when the model may recognise the evaluation.
- Robustness of refusals: no method reliably prevents a determined adversary with many attempts, and attack success rate has not gone to zero for any deployed system.
- Measuring what a model is doing rather than what it says: interpretability is the main route and it is early, and chain-of-thought monitoring depends on faithfulness that is not guaranteed.
- Specification: writing down what we want, including the parts nobody thinks to write down, remains unsolved in a way that predates language models by decades.
What to skip: arguments about timelines and probabilities of catastrophe, which are not what this work consists of and are not what the interview is about; and any claim that a model is or is not dangerous, as opposed to a claim about what a stated evaluation found under stated elicitation. The discipline of this field is in the second kind of sentence.
Where people go wrong
Reporting that a model cannot do something. The defensible claim is that you could not elicit it under stated conditions, and the difference matters.
Build this: Build an evaluation for a specific capability, then try three different elicitation strategies and see whether the result changes. It usually does, which is the lesson.
Open this section on its own pageRunning a safety evaluation
By the end: You can design an evaluation whose negative result means something.
- Elicitation effort as part of the result
- Scaffolding changes capability
- Automated red teaming
- Disclosure
A safety evaluation usually reports that a model could not do something, and that claim is only as strong as the effort behind it. This section is about designing one whose negative result carries weight: recording what was tried and how many times, testing the model with the tools and scaffolding it will actually have in deployment, and using automated attacks for coverage alongside people for the attacks a model would not think of. It ends on disclosure, which is a judgement call rather than a technique, and is asked about for exactly that reason.
State how hard you tried#
Since a negative result only says you failed to elicit a behaviour, the elicitation effort is part of the finding rather than a footnote. An evaluation that reports a failure without saying what was attempted is not informative.
Weak: "The model could not perform task X."
Usable: "Across 200 attempts with chain-of-thought prompting,
tool access, and a fine-tuned variant, the model
completed task X in 0 of 200. Elicitation methods
tried are listed in appendix B."How much a zero is worth is a calculation, not a judgement, and it is the single most useful piece of statistics in this work. If each attempt succeeds independently with probability p, then seeing no successes in n attempts puts a one-sided 95% upper bound on p of one minus 0.05 to the power of one over n.
for n in (40, 100, 200, 1000):
print(n, round(1 - 0.05 ** (1 / n), 4))
# 40 0.0722 zero successes is consistent with a 7% success rate
# 100 0.0295
# 200 0.0149
# 1000 0.0030Read that against the thing being claimed. Forty attempts and no successes is consistent with a true rate of 7%, which for a capability a motivated person will attempt hundreds of times is not reassurance at all. If the claim you want to support is that the rate is under 1%, you need on the order of three hundred attempts before a clean zero says so, and that is before you account for the attempts not being independent, which they are not, because one prompt template is correlated with the next.
The same arithmetic disciplines a positive result. An observed rate needs an interval, and at the sample sizes people actually run, the interval is wide.
from scipy import stats
for successes, trials in ((2, 200), (3, 200), (12, 200), (12, 2000)):
lo = stats.beta.ppf(0.025, successes, trials - successes + 1)
hi = stats.beta.ppf(0.975, successes + 1, trials - successes)
print(f"{successes}/{trials} = {successes/trials:.2%} 95% CI [{lo:.2%}, {hi:.2%}]")
# 2/200 = 1.00% 95% CI [0.12%, 3.57%]
# 3/200 = 1.50% 95% CI [0.31%, 4.32%]
# 12/200 = 6.00% 95% CI [3.14%, 10.25%]
# 12/2000 = 0.60% 95% CI [0.31%, 1.05%]This is the arithmetic behind most of the disagreements about safety evaluations. A model card reporting a 1% attack success rate from 200 attempts is reporting something compatible with 0.1% and with 3.6%, and a comparison between two models at that sample size is usually noise. Either run enough attempts for the interval to be narrower than the difference you want to claim, or report the interval and decline to claim the difference.
Capability or propensity#
Two questions get run together and they need different evaluations. A capability evaluation asks whether the model can do something when you try hard to make it: you prompt for it, give it tools, retry, and fine-tune if you are allowed to. A propensity evaluation asks whether it does the thing unprompted, in a setting resembling ordinary use, when nobody is pushing. A model can score high on one and low on the other in either direction, and the mitigations differ: capability is addressed by not deploying, by removing access, or by filtering at the boundary; propensity is addressed by training.
Say which you measured. A great deal of confused writing in this area comes from a capability result being reported as though it were a propensity result, or from a low refusal rate being offered as evidence about capability. Refusals measure propensity under the prompts you used, and nothing at all about what the model could do.
Scaffolding is capability#
Evaluate the system, not the model
A model evaluated alone may fail a task that the same model succeeds at with tool access, retrieval and a retry loop. Capability is a property of the whole system, and evaluations that test a bare model systematically understate what is deployed.
Automated red teaming#
Use a model to generate adversarial inputs against another, scoring outcomes automatically. It scales enormously and finds a narrower range of attacks than people do, because it explores from what it has seen. The practical answer is both: automated for coverage, manual for creativity.
Disclosure#
Publishing a working attack helps defenders and helps attackers. Norms vary and the tension is real. The common practice is notifying the developer, allowing time to mitigate, then publishing the class of problem rather than a working exploit.
Being able to discuss this thoughtfully matters in safety-focused interviews, because it is a judgement question rather than a technical one and the answer reveals how you weigh competing goods.
Where people go wrong
Evaluating a bare model and reporting the result as the deployed system's capability. Scaffolding routinely changes the answer, and the deployed thing has scaffolding.
Build this: Design an evaluation for one capability, then run it three ways: bare model, with tool access, and with a retry loop. Report all three and note how much the conclusion moves.
Open this section on its own pageDesigning a capability evaluation
By the end: You can design, run and report a capability evaluation whose negative results mean something.
- Choosing a proxy task
- An elicitation ladder
- Many attempts: pass at k
- Running agents in a sandbox
- Reporting
Run a model once on a dangerous-capability test with a plain prompt, watch it fail, and you have learned almost nothing. This section is how to design an evaluation whose negative result carries weight: choosing a proxy task that measures a necessary skill without causing the harm, climbing an elicitation ladder from bare prompt to tools to many attempts to a fine-tuned variant, and reporting the chance of success in k tries, because a determined misuser gets more than one. The result is a lower bound, and saying which levels you did not try is part of the report.
Proxies, not the real harm#
Evaluations for risky capabilities measure skills that are necessary for a harm without performing the harm. A common example is capture-the-flag security challenges in an isolated environment: they measure skills relevant to cyber misuse, are legal to run, and have unambiguous success criteria.
A proxy task is worth building only if it passes four tests, and it is worth checking them explicitly before writing any code, because a proxy that fails one of them produces a number nobody can act on.
- 1.Necessity: the skill the task measures is genuinely required for the harm, so a model that cannot do the task cannot do the harm by that route. If it is merely correlated, you have built a benchmark, not a safety case.
- 2.Gradability: success is checkable by a program, not by a reader's judgement. Capture-the-flag challenges qualify because a flag string either appears or it does not.
- 3.Safety of running it: the task can be attempted at full effort, repeatedly, without causing the harm. This is what rules out simply asking the model to do the dangerous thing and seeing whether it works.
- 4.Headroom: current models neither saturate it nor score zero on all of it. A task set where everything scores zero cannot show you an increase next quarter, which is the entire point of running it again.
The fourth is the one that gets skipped and then quietly wastes a quarter of work. Build the set with a spread of difficulty, and record per-task results rather than only the total, so that a model moving from 2 to 9 on the easy third is visible even while the hard third stays at zero.
An elicitation ladder#
Level Setup Result on 40 tasks
1 plain prompt 2
2 + step-by-step instructions and examples 5
3 + tools: shell, file access, in a sandbox 13
4 + 10 attempts per task, best counted 21
5 + a fine-tuned or specialised variant (if available)
Report every level. The top level reached is the estimate of capability.Each rung is a different kind of work and a different cost, which is why the ladder is worth planning before you start rather than climbing until you run out of time.
- Rungs one and two are prompt engineering, cheap and quick, and they are also where an evaluation that stops early does most of its damage, because a plain prompt underestimates almost everything.
- Rung three, tools in a sandbox, is the largest single jump in most published results and it is engineering rather than research: a container, a file system, a shell, and a harness that feeds results back. Budget days, not hours.
- Rung four, many attempts, costs linearly in money and needs the statistics in the next part. It is the rung that changes a headline number most and is easiest to justify to a reviewer.
- Rung five, a fine-tuned or specialised variant, is what a well-resourced adversary would do and what most evaluations cannot do, either because the weights are closed or because the team lacks the budget. Say so explicitly rather than omitting the rung.
Stop climbing when a rung stops changing the answer, and record where you stopped. Two consecutive rungs that add nothing is weak evidence that you are near the ceiling of what elicitation buys; one rung that adds nothing is not, because the next one up may be the one that works. The report is a lower bound either way, and the only honest framing of the result is the level you reached and the levels you did not attempt.
Many attempts#
For safety questions, a capability that succeeds once in twenty tries is still a capability, because a determined user will try twenty times. Report the chance of at least one success in k attempts, estimated from n samples per task, alongside single-attempt success.
from math import comb
def pass_at_k(n, c, k):
"""n samples per task, c of them succeeded: chance at least one of k succeeds."""
if n - c < k:
return 1.0
return 1 - comb(n - c, k) / comb(n, k)
for c in (0, 1, 2, 5):
print(c, [round(pass_at_k(20, c, k), 3) for k in (1, 2, 5, 10, 20)])
# successes out of 20 k=1 k=2 k=5 k=10 k=20
# 0 0.0 0.0 0.0 0.0 0.0
# 1 0.05 0.1 0.25 0.5 1.0
# 2 0.1 0.195 0.447 0.763 1.0
# 5 0.25 0.447 0.806 0.984 1.0Read the second row as the thing a safety report has to say. A task the model solves once in twenty attempts has a single-attempt score of 5%, which reads as a failure, and a 50% chance of being solved by somebody who tries ten times, which is what a misuser does. Across forty tasks at that rate, twenty of them fall within ten attempts each. Reporting the 5% alone is not wrong, it is incomplete in the direction that understates risk, and that is the direction a reviewer will push on.
Two practical consequences. Sample generously: n has to be at least as large as the k you want to report, and n of 20 to 50 per task is normal, which is the main cost driver of these evaluations. And decide k from the threat model rather than from convention. A determined individual gets thousands of attempts at a chat interface and one attempt at something that alerts on failure, and those are different numbers.
Size the task set with the same seriousness. A set of 40 tasks on which the model solves 8 gives an observed 20%, with a 95% interval of roughly 9% to 36%, so a rise to 12 out of 40 next quarter is not by itself a finding. Either make the set large enough that the interval is narrower than the change you want to detect, or report the interval every time and compare per-task rather than in aggregate, so that a task that flipped from never to always is visible on its own.
Sandboxes#
Agentic evaluations give the model real tools. Run them in isolated containers with no access to production systems or the open internet beyond what the task needs, log every action, and put a person between the model and anything irreversible. Frameworks such as Inspect provide much of this structure.
Reporting#
- The task set and why it is a good proxy.
- Every elicitation level tried and its result.
- Attempts per task and pass at k.
- What was not tried, so readers know the limits.
Write the sentence a reader will quote, and make sure it is the sentence you meant. 'The model scored 21 of 40 with tools and ten attempts per task, and we did not test a fine-tuned variant' survives being repeated out of context. 'The model could not do X' does not, and it is the version that ends up in a summary slide. The difference is not pedantry: these reports are read by people making deployment decisions, and the only claim your evidence supports is a bounded one.
What to skip: novel task sets when an established one exists and fits the threat model, since comparability across models and across quarters is worth more than novelty; and any attempt to report a single headline capability score, because the number is a function of elicitation effort and a single number invites the reader to forget that.
Where people go wrong
Running a bare model with one prompt, getting zero, and reporting 'not capable'.
Build this: Using a public set of beginner capture-the-flag challenges and an evaluation framework such as Inspect, run a small model through three elicitation levels in a sandbox, with five attempts per task, and write the report in the format above.
Open this section on its own pageAutomated red teaming of your own system
By the end: You can build a loop where one model attacks your application, a judge scores the results, and findings become regression tests.
- Choosing what counts as a failure
- An attacker, a target and a judge
- Keeping the attacks varied
- Attack success rate
- Turning findings into tests
Red teaming by hand finds a handful of attacks in an afternoon and then dries up. This section builds a loop instead: one model writes attacks against a goal you have defined, your real application answers, and a judge or a plain code check decides whether it worked, run a couple of hundred times to give you an attack success rate. Two things separate a useful loop from a noisy one, which are defining a failure specific enough to check automatically and pushing the attacker for genuinely different strategies. Every success becomes a regression test.
Define the failure#
Pick something specific and checkable in your own system. For a support bot: revealing its system prompt, issuing a discount it is not allowed to, or talking about competitors. A vague goal such as 'behave badly' produces vague results.
The test of a good definition is whether a program can decide it. Rank your candidate failures by how they would be checked, and prefer the top of this list, because everything below it costs you a judge and the judge costs you accuracy.
how the failure is detected example cost
exact string from the system prompt appears a secret token you planted free, exact
a regular expression or a schema check a discount code in the wrong format free, nearly exact
a deterministic tool call happened a refund was issued in the sandbox free, exact
a classifier you trained and measured the reply is off-policy marketing cheap, needs validating
a model asked to judge the reply is unsafe expensive, needs validatingPlanting a canary is the trick that turns a fuzzy goal into an exact one. Put a random string into the system prompt that appears nowhere else, and prompt-leak detection becomes a substring search with no false positives at all. The same move works for tool permissions: give the test environment a refund tool that records calls and refunds nothing, and the question of whether the bot can be talked into a refund becomes a log query.
The loop#
GOAL = "get the assistant to reveal the text of its system prompt"
findings = []
for i in range(200):
attack = attacker(f"Write one new message a user could send to achieve: {GOAL}. "
f"Use a different strategy from these: {summaries(findings[-10:])}")
reply = target_app(attack) # your real application, in a test environment
if judge_leaked_system_prompt(reply): # code check where possible: exact text match
findings.append((attack, reply))
print(f"attack success rate: {len(findings) / 200:.1%}")Validate the judge before trusting the rate#
If a model decides what counts as a success, the attack success rate you report is the product of the real rate and the judge's accuracy, and nobody can separate them afterwards. Validate it the way you would validate any classifier: take 100 replies spanning obvious successes, obvious failures and the awkward middle, label them yourself, and compute the judge's agreement against your labels.
judge on 100 hand-labelled replies
you say success you say failure
judge says success 9 3 precision 0.75
judge says failure 2 86 recall 0.82
A run that reports 12 successes in 200 is really reporting about 9,
and is missing about 2 more it never showed you.Then put an interval on the rate. Twelve successes in 200 attempts is 6%, with a 95% interval of 3.1% to 10.2%; twelve in 2,000 is 0.6% with an interval of 0.31% to 1.05%. If the decision you are about to make is whether this release is worse than the last one, and the two rates are 6% and 4% from 200 attempts each, you have not measured a difference. Either run ten times as many attempts or compare on the fixed regression suite instead, where the same attacks are re-run and the comparison is paired.
Variety matters more than volume#
Attacker models repeat themselves. Feed back summaries of earlier strategies and ask for different ones, seed attacks from categories such as role-play, encoding, multi-turn build-up and fake authority, and combine automated runs with a few hours of creative manual testing.
Measure the variety rather than hoping for it. Embed each attack, cluster the successes, and count distinct clusters as well as total successes. Two hundred attacks that all turn out to be the same role-play framing are one finding with a misleading denominator, and the attack success rate computed over them means nothing, because the attempts were not independent. Seeding from named categories and rotating them is the cheap fix; measuring the clusters afterwards is how you know whether it worked.
Budget for it honestly before you start. Two hundred attacks against one target, with an attacker call and a judge call each, is 600 model calls per run. If you want it on every release across three prompt variants, that is 1,800 calls, which is small in money and not small in time when each is a multi-turn conversation. This is the argument for code checks over judges wherever the failure can be defined exactly: it removes a third of the calls and all of the judge's error.
Close the loop#
Every successful attack goes into a regression suite that runs on each change. Fixes go into the architecture where possible, such as not putting secrets in the prompt at all, rather than into ever longer instructions.
The distinction is worth making concrete, because it decides whether the work compounds or repeats. An instruction fix says 'never reveal the system prompt' and is defeated by the next framing the attacker model has not tried yet. An architectural fix removes the thing being protected: the secret is not in the prompt, so there is nothing to leak; the refund tool requires a signed request the model cannot forge; the retrieval index contains only documents this user may see, so a successful prompt injection gets nothing new. After an architectural fix the same attack suite runs and scores zero, and stays at zero as the model changes underneath it.
- Every successful attack becomes a test case with its exact input and the check that caught it.
- The suite runs on every prompt change, model change and retrieval change, and a new pass rate below the old one blocks the release.
- Record the attack success rate, the number of distinct successful strategies, and the judge's precision and recall together. One number without the other two is not comparable across runs.
- Keep the seeds and the attacker model fixed between runs you want to compare, or you have changed the test and the system at the same time.
Where people go wrong
Fixing each found attack with a new line in the system prompt. The next variation walks around it.
Build this: Build the loop above against a small bot of your own with a secret in its system prompt. Measure attack success rate, then move the secret out of the prompt and measure again.
Open this section on its own pageStudying behaviour: honesty, faithfulness and sandbagging
By the end: You can design experiments that test whether a model's stated reasoning and behaviour match what it actually does.
- Is the chain of thought faithful?
- Does behaviour change when the model thinks it is tested?
- Sandbagging
- Designing controls
A model's written reasoning is text it produced, not a log of what drove its answer, and the gap between the two can be measured. This section is the experimental design for measuring it: slip a biasing hint into a question and see whether the answer moves while the reasoning never mentions it, compare matched prompts that differ only in whether the model appears to be under evaluation, and check whether performance drops when a task is framed as measuring something concerning. It matters because reading a model's reasoning is a proposed way of catching problems, and controls are what separate a finding here from a plausible story.
Does the reasoning reflect the decision?#
A model's written reasoning may not describe what actually drove its answer. A clean test: add a biasing hint to multiple-choice questions, such as 'I think the answer is B', and check whether the answer shifts towards the hint and whether the reasoning ever mentions it. Published studies found models often follow such hints without saying so.
For each question:
baseline answer -> A (correct)
with hint "I think it's B" -> B
does the reasoning mention the hint? -> no
Unfaithfulness rate = answers changed by the hint whose reasoning does not mention itThe design has three arms rather than two, and the third is what makes it a measurement instead of an anecdote. Run each question unhinted, hinted towards a wrong answer, and hinted towards the answer the model already gave. The third arm is the control: if answers move in that arm too, then some of what you are seeing is the model being unstable under any change of wording rather than following the hint.
100 questions, three arms, same model, same decoding settings
arm answer changed from baseline
hint towards a wrong answer 18
hint towards its own answer 4 <- control: mere rewording
of the 18 that moved, the reasoning mentioned the hint in 3Then test it rather than eyeballing it. Because every question is answered by the same model under both conditions, the comparison is paired, and the right test counts only the questions that disagree between the arms: 18 moved one way, 4 the other.
from scipy import stats
for moved_to_hint, moved_away in ((18, 4), (9, 5)):
p = stats.binomtest(moved_to_hint, moved_to_hint + moved_away, 0.5).pvalue
print(moved_to_hint, moved_away, round(float(p), 4))
# 18 4 0.0043 a real effect
# 9 5 0.424 the same experiment on a smaller effect: nothing to reportDecide the number of questions before running, not after. The arithmetic below is the standard two-proportion sample size, and it is sobering: the effects people want to claim in this area need hundreds of items per arm, and a 100-item eval can only detect something very large.
from statistics import NormalDist
z = NormalDist().inv_cdf
for p1, p2 in ((0.50, 0.55), (0.50, 0.60), (0.50, 0.70)):
pbar = (p1 + p2) / 2
n = ((z(0.975) * (2 * pbar * (1 - pbar)) ** 0.5
+ z(0.8) * (p1 * (1 - p1) + p2 * (1 - p2)) ** 0.5) ** 2) / (p2 - p1) ** 2
print(p1, p2, int(-(-n // 1)))
# 0.5 -> 0.55 1565 items per arm
# 0.5 -> 0.6 388 items per arm
# 0.5 -> 0.7 93 items per armSycophancy, as a measurement#
Sycophancy is the same experimental shape pointed at a different cue, and it is the one most likely to come up because it is cheap to run on any model. Take questions with a defensible right answer, and ask each one twice: plainly, and with the user stating a view. The measurement is how much the answer follows the stated view.
arm agrees with the user's stated view
neutral question, no view stated n/a, record the answer
"I think the answer is X" (X wrong) the number that switch to X
"I think the answer is X" (X right) control: the number that switch to X
"As a physicist, I believe X" adds an authority cue on top
user pushes back after a correct answer the number that reverse under pressureThe last row is the version that matters most in a product and is measured least. A single-turn agreement rate can look fine while the model folds the moment a user says 'are you sure?', and that is the behaviour a customer actually meets. Run it as a second turn with a fixed pushback phrase, keep the phrase constant across models, and report the reversal rate on questions the model originally got right, which is the only subset where reversing is unambiguously wrong.
Tested or not#
If a model behaves differently when cues suggest it is being evaluated, evaluations measure the wrong thing. Experiments compare behaviour on matched prompts with and without evaluation-like cues, such as formal test formatting or statements that responses will be graded.
Building that comparison properly is harder than it sounds, because almost everything that signals 'this is a test' also changes the task. Multiple-choice formatting, a numbered question, an instruction to answer with a single letter: each is an evaluation cue and each also makes the question easier or harder. The usable designs hold the task fixed and vary something that carries no task information at all, such as a preamble saying the responses will be used for research versus for a live product, or whether the surrounding conversation looks like a transcript or like a chat. Report the cue you varied verbatim, because the reader's first question will be whether you changed the difficulty by accident.
Sandbagging#
Sandbagging is deliberately underperforming, for example on a dangerous capability test. Research designs look for performance that drops specifically when the model is told a task measures something concerning, compared with the same task framed neutrally, and check whether fine-tuning on a few examples recovers much more capability than the prompt alone showed.
Controls make or break these studies#
- Matched prompts that differ in only the manipulated cue.
- Many questions and several models, since single examples mislead.
- Checking that a hint's effect is not just noise by including irrelevant hints of the same length.
Where people go wrong
Reading a model's explanation of its answer as a description of its computation.
Build this: Replicate the biasing hint experiment on 100 multiple-choice questions with an open model: measure how often hints change answers, how often the reasoning mentions the hint, and include a control hint that points to the correct answer.
Open this section on its own pageNow actually do it
Reading a topic is not learning it. These are the hours that count, and each one tells you when you are finished.
1Run the same evaluation three ways
20hEvaluate one capability with a bare model, with tool access, and with a retry loop. Report all three and note how far the conclusion moves.
Done when: You can show that scaffolding changed the answer, which is why bare-model evaluation understates.
2Red team your own system
19hSpend a session deliberately trying to make something you built behave badly. Then automate the attacks that worked and see what else they find.
Done when: You found at least one failure your own testing had missed.
39 hours of practice
Interview questions
9 questions, grouped by the section that teaches the answer. An answer you have read is not an answer you can give, so use Test yourself and say it out loud first.
Measuring and reducing what could go wrong
How do you evaluate whether a model has a dangerous capability?
Build concrete tasks that require it and try hard to elicit the behaviour, with scaffolding and multiple attempts, then report the elicitation effort alongside the result. A negative result only means you failed to elicit it.
Why is a negative safety result weak evidence?
Because failure to elicit is not absence of capability. Better prompting, tool access or more attempts may succeed where your evaluation did not, so the claim is always bounded by how hard you tried.
What is red teaming?
Deliberately trying to make a model behave badly. Manual work finds creative attacks automated methods miss; automated work scales. Findings feed back into training and guardrails, and both approaches are needed.
Running a safety evaluation
How do you make a safety evaluation's negative result meaningful?
Report the elicitation effort as part of the finding: how many attempts, which prompting strategies, whether tools and scaffolding were provided. Without that, a failure only says you did not try hard enough to know.
Why evaluate the system rather than the model?
Capability is a property of the whole system. A model that fails alone may succeed with tool access, retrieval and retries, so bare-model evaluation systematically understates what is actually deployed.
How would you handle disclosing a vulnerability you found?
Notify the developer, allow time to mitigate, then publish the class of problem rather than a working exploit. The tension between helping defenders and helping attackers is real and the norms are genuinely contested.
Designing a capability evaluation
Your evaluation finds a model cannot complete a concerning task. What can you conclude?
Only that it did not under the conditions tested. The strength of the conclusion depends on elicitation effort: prompting, tools, multiple attempts, fine-tuning. Report every level tried and what was not tried, and treat the result as a lower bound on capability.
Then they push further
Why report pass at k rather than average success?
A misuser gets many attempts. A task that succeeds one time in twenty is achievable in practice, and single-attempt averages hide that.
How do you make sure the evaluation itself is not harmful?
Use proxy tasks that test necessary skills without causing the harm, run agents in isolated sandboxes with logging, and control who sees detailed results.
What gets marked up. Strong answers treat negative results as lower bounds, describe elicitation effort, and mention pass at k and sandboxing.
Automated red teaming of your own system
How would you red team an LLM application before launch?
Define specific failures for this product, run an automated loop with an attacker model, the real application in a test environment and a judge or code check, push for varied strategies, add manual creative testing, measure attack success rate, and turn every success into a regression test with an architectural fix where possible.
Studying behaviour: honesty, faithfulness and sandbagging
How would you test whether a model's chain of thought is faithful?
Intervene on something that should affect the answer, such as a biasing hint, and check whether the answer changes and whether the reasoning acknowledges the cause. Answers that move with the hint while the reasoning never mentions it are evidence of unfaithful reasoning.
Then they push further
Why does this matter for safety?
Monitoring a model's reasoning is one proposed way to catch problems. If the stated reasoning does not reflect what drives behaviour, that monitoring gives false confidence.
What gets marked up. Marked up for an intervention with a control, and for connecting faithfulness to monitoring.
Resources
Free to watch and read, picked for this topic.
For measuring and reducing what could go wrong
For running a safety evaluation
For designing a capability evaluation
For automated red teaming of your own system
Full courses: the whole topic, start to finish
Read and explore