Surrogates preserve utility better than tokens, and they introduce a risk that tokens do not.
<PERSON_1> is obviously not a person. Megan Alvarez is obviously a person, and is not the person. If a surrogate escapes the boundary where values are restored, a human downstream has no way to tell, and will act on it as real. The failure is not that someone is careless. It is that a well-chosen surrogate is designed to be indistinguishable, and you have removed the signal a reader would need in order to doubt it.
If you use surrogates, three rules.
The restore boundary must be explicit and total. One place in the code restores values, and nothing renders model output that has not passed through it.
Anything that escapes must be labelled. If a surrogate can reach a log, an export, a webhook, or a downstream system, it must carry a marker saying so.
Never use surrogates where the output feeds an action. Summaries for humans, yes. Arguments to a tool that sends an email, no. Chapter 15 has more on why model-composed values reaching actions is its own category of problem.
Work through four questions for each LLM feature. They take ten minutes and they prevent the silent-wrong-answer class entirely.
What does the task actually operate on? Write the sentence. "Classify the urgency of this ticket from its text." Urgency comes from the complaint, not the complainant. The name can go.
Which entities are load-bearing? For each entity type your detector catches, ask whether removing it changes the answer. Most of the time, for most entity types, it does not. When it does, you have found the ones that need a reversible safeguard rather than removal.
Can a generalisation carry the signal? Usually yes, and this is the most under-used answer in the book. The task rarely needs the exact date of birth, exact salary, exact ZIP code, or exact timestamp. It needs the decade, the band, the region, the month.
What happens if the model gets it wrong? If output goes to a human who can check it against the source, a degraded answer is an annoyance. If it triggers an action, a degraded answer is an incident, and you should be much more conservative about masking anything the decision depends on.
There is now measured evidence on how much this costs, and the headline is that it varies far more than you would guess. Deußer et al. (2026) ran five anonymisation strategies across eleven benchmarks and five models. Three findings are worth carrying into your own design.
The damage is task-specific, not uniform. On RGB, a retrieval-grounded benchmark, scores fell by between 0.22 and 0.47. On TruthfulQA, anonymisation improved results across every model tested, with Llama-3.1 gaining 8 percentage points, apparently because stripping named entities stopped the model reaching for incorrect memorised associations. The same safeguard helped one task and gutted another.
More capable models lose more. Qwen2.5-72B degraded by 6.9 percentage points on average against 2.3 for the much smaller Teuken-7B. The stronger model was relying on entity knowledge that anonymisation removed. Upgrading your model does not buy you headroom here, and may cost you some.
Telling the model does not help. Adding a prefix explaining that the text has been anonymised produced no significant or consistent improvement. If you were planning to solve this with prompt engineering, that is the experiment already run.
Which leads to the one thing you should actually do: evaluate your task with and without the safeguard applied.
Take fifty real examples. Run them through the model with the original text and with the de-identified text. Compare the outputs. Not with an automated metric, at least not at first; read them side by side. You will find out in an afternoon whether your safeguard costs you nothing, costs you a little, or has quietly broken the feature.
[Fact]
public async Task Deidentification_DoesNotDegradeSummaryQuality()
{
foreach (var sample in EvalSet.Load(50))
{
var raw = await _model.SummariseAsync(sample.Text);
var treated = await _model.SummariseAsync(Deidentify(sample.Text).Text);
// Judged offline and recorded; this asserts the artefact exists,
// the comparison itself is a human review.
EvalReport.Record(sample.Id, raw, treated);
}
Assert.True(EvalReport.AgreementRate >= 0.90);
}Teams run detector accuracy tests and almost never run task quality tests. The result is a privacy control that measurably works and a feature that quietly stopped working, and the second one is what users experience.
When the answer comes back that the task genuinely needs the real value, do not go looking for a cleverer mask. There is no mask that both hides a value and preserves it. What you need is a different design, where the sensitive value never needed to be in the prompt in the first place.
That is the rest of the book.
The plausibility hazard, the four per-task questions, and the rule against surrogates where output feeds an action are the author's argument. No incident data is cited for surrogates reaching end users, and the text does not assert that it has happened.
Download the full PDF for free?
Free download — no account required