Command Palette

Search for a command to run...

Hectal
PHASE 10Advanced ~21 min· topic 5 of 9

Topic 10.5

Personal Data

In one line

Personal data (PII) is anything that can identify a person. Detect and redact it before it reaches a model or a log, know that simple detectors both miss things and flag innocent text, and keep only what you need for only as long as you need it.

Think of it like this

Before a school photocopies a class list for a trip company, a teacher covers the home addresses and phone numbers with a strip of paper. The company still gets names and ages, which is all it needs. She does it because once the copy leaves the building she cannot take it back. Redacting personal data before it reaches a model or a log is the same strip of paper.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

PII
Personally identifiable information: data that identifies a person alone or when combined with other data.
Redaction
Replacing sensitive values with a label such as [EMAIL] so they are not seen or stored.
Pseudonymisation
Replacing real values with stand-ins, keeping a private table to restore them later.
False positive
The detector flags something that is not personal data (a date flagged as a phone number).
False negative (a miss)
The detector fails to flag something that is personal data.
Luhn check
A checksum that valid card numbers satisfy. It rejects most random digit runs.
Retention
How long data is stored before deletion.

Step by step

01Step 1: write one pattern at a time

An email has letters, digits and a few symbols, an @, a domain, a dot and at least two letters. The pattern says exactly that. It is simple on purpose: the full email standard is huge, and a simple rule that catches the common shape is what you want here.

main.pywhole filepython
EMAIL = re.compile(r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}")

02Step 2: cards need a second opinion

Any 13 to 16 digit run looks like a card number, so the program redacts only runs that also pass the Luhn check. The test card in the example passes; a random run usually does not. Doing cards before phones matters: otherwise the phone pattern would swallow part of the card.

Step 2: cards need a second opiniondiagram
Rendering diagram…

03Step 3: read the results honestly

Email, phone and card are redacted. The order id and the date are also redacted: false positives that make the text less useful. The last case is a miss: a name, a city and an email spelled out in words pass through untouched. Show these limits to your team; a redactor sold as 'removes all PII' is a trap.

04Step 4: choose how to fail

If a miss is costly (health or payments), redact more aggressively and accept false positives, or block the request and ask the user to remove the data. If a false positive is costly (order ids matter), make the patterns stricter or add context words such as 'phone' or 'call'. There is no free setting.

05Step 5: where to put it

Redact at the edge of your system: before the prompt is built, and again before anything is logged. Do it in one shared function so no code path forgets. Then test the function with a table of real-looking samples, including the misses you know about.

Try it yourself

  1. 1

    Predict the six outputs

    Before running, write down the out: line for each case. Which ones did you get wrong?

  2. 2

    Fix the date false positive

    Make the phone pattern stricter so 2024-01-15 is no longer redacted, for example by requiring that a phone has at least 10 digits (not just 10 characters). Which of your other cases still pass?

  3. 3

    Add numbered placeholders

    Change redact to return [EMAIL_1], [EMAIL_2] for each different email and also a dictionary mapping labels to originals. Then write restore(text, mapping) to put the values back.

Code & diagrams

A PII redactor built by hand, with its false positives and misses New tab

All numbers and addresses are made up. The card number is a test number that passes the Luhn check. Read the two false hits and the miss.

Sign in to run this example in your browser.

Expected output

email:
  in:  Write to ana@example.com about the invoice.
  out: Write to [EMAIL] about the invoice.
phone:
  in:  Call me on +91 98765 43210 tomorrow.
  out: Call me on [PHONE] tomorrow.
card:
  in:  The card 4539 1488 0343 6467 was charged.
  out: The card [CARD] was charged.
false hit: order id:
  in:  Order 1234567890 has shipped.
  out: Order [PHONE] has shipped.
false hit: date:
  in:  The meeting is on 2024-01-15.
  out: The meeting is on [PHONE].
miss: spelled out:
  in:  Ana Rao lives in Pune, write ana at example dot com.
  out: Ana Rao lives in Pune, write ana at example dot com.

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Redact phones before cards

In redact, run PHONE.sub before the card step (swap the order of the last two steps) and run the card case. Read the out: line of the card case.

terminal
$ Run
── what you'll see ──
email:
in: Write to ana@example.com about the invoice.
out: Write to [EMAIL] about the invoice.
phone:
in: Call me on +91 98765 43210 tomorrow.
out: Call me on [PHONE] tomorrow.
card:
in: The card 4539 1488 0343 6467 was charged.
out: The card [PHONE] 6467 was charged.
false hit: order id:
in: Order 1234567890 has shipped.
out: Order [PHONE] has shipped.
false hit: date:
in: The meeting is on 2024-01-15.
out: The meeting is on [PHONE].
miss: spelled out:
in: Ana Rao lives in Pune, write ana at example dot com.
out: Ana Rao lives in Pune, write ana at example dot com.

Myth vs fact

Myth

A regular expression redactor removes all PII.

Fact

It removes values with a fixed shape. Names, addresses and anything spelled out or disguised pass through, and some innocent text is flagged.

Myth

If the provider promises not to train on my data, I do not need to redact.

Fact

Redaction still reduces breach impact, log exposure, legal scope and what you must delete on request. Less data is simply safer.

Myth

Logs are not user data.

Fact

Logs hold prompts and replies, which hold personal data. They need redaction, retention limits and access control.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Combine detectors: patterns for structured values, a named-entity recogniser or a classifier for names and addresses, and a policy for what to do on a hit (mask, block, ask). Measure precision and recall on a labelled sample (Topic 9.3).

  • ▸

    Keep the pseudonym map in memory for the length of the request and never log it. If you must store it, encrypt it and delete it with the conversation.

  • ▸

    Redaction changes meaning: a model summarising '[PERSON] met [PERSON]' loses who did what. Use numbered placeholders when relationships matter.

  • ▸

    Handle locale-specific formats: phone and ID formats differ by country, and a pattern written for one country misses another's. Test with your real markets.

Remember this

  1. 1

    Why this exists. Users paste emails, invoices, medical notes and CVs into LLM apps. Without care that text goes to a provider's servers, into your logs, into analytics and sometimes into caches and datasets. Every extra copy is another place for a breach, another thing to delete when a user asks, and often a legal duty (privacy laws such as the GDPR in Europe and India's DPDP Act apply to personal data; this course is not legal advice, so check with your legal team which laws apply to you). The simplest rule: data you never collect cannot leak.

  2. 2

    What counts as PII. Names, email addresses, phone numbers, postal addresses, government and bank IDs, card numbers, account numbers, IP addresses and device IDs, photos, and in many laws also health, religion or other special categories. Combinations count too: a job title plus a small office can identify one person.

  3. 3

    Detecting it: patterns. Regular expressions (short patterns that describe a text shape, such as "letters, an @, a domain") find things with a fixed shape: emails, phone numbers, card numbers (add the Luhn check, a checksum real card numbers satisfy, to cut false matches). The example builds three by hand. Patterns are quick, cheap, run locally and are explainable, so they are the first layer.

  4. 4

    Detecting it: their limits. Look at the output: an order id of ten digits is flagged as a phone number, a date such as 2024-01-15 is flagged too (false positives), while names, ana at example dot com and addresses are not found at all (misses). Names and free-form addresses need a trained recogniser (named-entity recognition: a model that marks the names, places and organisations in text) or a general model, which brings its own errors. Measure both kinds of mistake on real samples (Phase 9) and choose which error is worse for you: usually a missed card number is worse than a masked order id.

  5. 5

    Redact, mask or pseudonymise. Redaction replaces the value with a label ([EMAIL]). If the model needs to refer to the thing (draft a reply to 'the customer'), use numbered placeholders ([EMAIL_1]), keep the mapping in your server's memory only for this request, and put the real value back in the final reply. The model then does its job without ever seeing the data. Decide per field: a model that checks tone does not need a name; a model that drafts the email to the address does need it in your code, though not necessarily in the prompt.

  6. 6

    Retention and logs. Decide how long each kind of data lives and delete it on schedule. Redact before logging (Topic 11.2), keep prompts out of long-lived analytics, and be able to delete one user's data on request across the database, caches, vector store and any saved conversations. Check the provider's retention settings; some offer zero-retention terms for qualified use. Treat test data the same way: real customer text does not belong in a golden set (Phase 9) unless it has been redacted.

Explain it without notes

01

Why should personal data be redacted before it reaches a model or a log?

02

What are false positives and false negatives in a PII detector, and which matters more?

03

Why add a Luhn check to a card-number pattern?

04

How can a model draft a reply to a customer without seeing the customer's email address?

Practice

01

Write mask_emails(text) that replaces every email address with [EMAIL_n] numbered from 1 in order of first appearance (the same address gets the same number), and returns (masked_text, mapping) where the mapping is a dict from label to address.

02

Write luhn_ok(number_string) and test it with "4539148803436467" and "1234567890123456".

Trade-offs

  • ↔

    Aggressive redaction protects more and breaks more meaning; tune per data type.

  • ↔

    A model-based detector finds names and addresses that patterns cannot, but adds cost and latency, and sends the raw text to a model first unless it runs locally.

  • ↔

    Keeping full conversations helps debugging and evaluation, and widens your breach and deletion duties; keep redacted copies and short retention.

Done when you can

  • Done when you can write email, phone and card patterns and explain what each misses.

  • Done when you can show a false positive and a false negative from your own redactor.

  • Done when you can pseudonymise with placeholders and restore them in the reply.

  • Done when you can say where in a pipeline redaction runs and why twice (prompt and log).

  • Done when you can set a retention rule for prompts, logs and caches.