Warum RAG-Pipelines bei naiver Anonymisierung versagen
Retrieval-Augmented Generation (RAG) stützt sich auf die semantische Ähnlichkeit zwischen einer Nutzerfrage und indexierten Dokumentabschnitten. Fragt jemand „Was hat Maria Rossi letzten Monat bestellt?“, sucht das Abrufsystem nach inhaltlich passenden Abschnitten. Ein großes Sprachmodell (LLM) formuliert aus dem gefundenen Kontext eine Antwort.
Das Problem entsteht beim Einlesen der Dokumente. Wenn Sie Dokumente vor der Erstellung ihrer Vektordarstellungen anonymisieren und dabei denselben Wert unterschiedlich ersetzen, geht die semantische Verbindung verloren:
- Dokument A: „Maria Rossi“ →
[PERSON_1] - Dokument B: „Maria Rossi“ →
[PERSON_3] - Dokument C: „M. Rossi“ →
[PERSON_7]
Die drei Dokumente sollten gemeinsam gefunden werden. Im Index erscheinen sie nun aber so, als bezögen sie sich auf drei verschiedene Personen. Dadurch bricht die Trefferquote beim Abruf ein. Das Sprachmodell erstellt aus nur einem Bruchteil des relevanten Kontexts unvollständige Antworten.
Das Problem: Inkonsistente Anonymisierung zerstört die Suche
Übliche Anonymisierungswerkzeuge sind für einzelne Dokumente und Sitzungen ausgelegt. Sie vergeben Platzhalter wie [PERSON_1] und [PERSON_2] der Reihe nach und speichern die Zuordnung nicht dauerhaft. Verarbeiten Sie dasselbe Dokument zweimal, können unterschiedliche Token entstehen.
Für RAG-Pipelines hat das drei Folgen:
- Die Suche über mehrere Dokumente hinweg scheitert: Derselbe Wert hat in verschiedenen Dokumenten unterschiedliche Token. Die Ähnlichkeitssuche übersieht deshalb zusammengehörige Abschnitte.
- Das schrittweise Erweitern des Index wird problematisch: Neue Dokumente beginnen mit einer neuen Tokenfolge. Dadurch können Token mit vorhandenen kollidieren. Ein neues
[PERSON_1]kann eine andere Person bezeichnen. - Die Anonymisierung der Suchfrage passt nicht zum Index: Wenn Sie eine Nutzerfrage vor der Suche anonymisieren, müssen deren Token genau mit den Token im Index übereinstimmen.
Die Lösung: konsistente Pseudonymisierung
Bei konsistenter Pseudonymisierung gilt eine feste Zuordnung: Derselbe eingegebene Wert erhält immer dasselbe Token. Eine dauerhaft gespeicherte Tabelle, etwa in einer Datenbank oder einem Schlüssel-Wert-Speicher, hält die Zuordnung für alle Dokumente und Sitzungen bereit.
Dafür gibt es zwei Wege:
Ansatz 1: Token aus Hashwerten
Berechnen Sie aus dem Wert einer Person einen Hashwert mit geheimem Schlüssel. Gleiche Eingaben ergeben denselben Hashwert. Zwei Vorkommen von „Maria Rossi“ erhalten somit identische Token. Ein geheimer Schlüssel (HMAC) verhindert die Rückrechnung.
import hmac, hashlib
HMAC_KEY = b"your-secret-key-32-bytes-minimum"
def consistent_token(entity_type: str, entity_value: str) -> str:
"""Erzeugt ein stabiles, gleichbleibendes Token für einen Wert."""
digest = hmac.new(
HMAC_KEY,
f"{entity_type}:{entity_value.strip().lower()}".encode(),
hashlib.sha256
).hexdigest()[:8]
return f"[{entity_type}_{digest}]"
# Beispiele:
# consistent_token("PERSON", "Maria Rossi") -> "[PERSON_3a7f9c2b]" (immer)
# consistent_token("PERSON", "maria rossi") -> "[PERSON_3a7f9c2b]" (gleich)
# consistent_token("PERSON", "John Smith") -> "[PERSON_b1e4a8d6]" (anders)Ansatz 2: Nachschlagetabelle mit fortlaufenden Nummern
Speichern Sie die Zuordnung von Werten zu Token dauerhaft. Beim ersten Auftreten erhält ein Wert das nächste verfügbare Token seiner Art. Bei späteren Vorkommen verwenden Sie die gespeicherte Zuordnung.
import json, pathlib
class PersistentMapping:
def __init__(self, path: str):
self.path = pathlib.Path(path)
self.data = json.loads(self.path.read_text()) if self.path.exists() else {}
self.counters = {}
def get_token(self, entity_type: str, entity_value: str) -> str:
key = f"{entity_type}:{entity_value.strip().lower()}"
if key not in self.data:
count = self.counters.get(entity_type, 0) + 1
self.counters[entity_type] = count
self.data[key] = f"[{entity_type}_{count}]"
self.path.write_text(json.dumps(self.data))
return self.data[key]
def reverse(self, token: str) -> str | None:
reverse_map = {v: k.split(":", 1)[1] for k, v in self.data.items()}
return reverse_map.get(token)
mapping = PersistentMapping("entity_mapping.json")
print(mapping.get_token("PERSON", "Maria Rossi")) # [PERSON_1]
print(mapping.get_token("PERSON", "Maria Rossi")) # [PERSON_1] (gleich)
print(mapping.get_token("PERSON", "John Smith")) # [PERSON_2]Umkehrbare Tokenisierung mit anonym.legal
anonym.legal bietet umkehrbare Tokenisierung, beispielsweise über das Werkzeug anonym_legal_anonymize_text seines MCP-Servers. Jeder Aufruf liefert eine session_id. Die Zuordnung der Token wird verschlüsselt gespeichert: standardmäßig für 24 Stunden oder mit der Einstellung persistent für bis zu 30 Tage. Wenn die Zuordnung über viele Dokumente eines gesamten Bestands hinweg gleich bleiben soll, führen Sie eine eigene Tabelle wie oben gezeigt. Angaben zur REST-Schnittstelle finden Sie in der API-Dokumentation bei anonym.legal.
// anonym.legal MCP-Server (Paket: anonym-legal-mcp-server)
// Werkzeug: anonym_legal_anonymize_text
{
"text": "Maria Rossi ordered from Berlin on Jan 15.",
"mode": "tokenize", // umkehrbares Ersetzen (Standard)
"persistence": "persistent", // Zuordnung 30 Tage gespeichert; "session" = 24 Stunden (Standard)
"sessionName": "rag-corpus-v1"
}
// Die Antwort enthält anonymized_text und eine session_id.
// Bewahren Sie die session_id auf, um die ursprünglichen Werte wiederherzustellen.Welche Arten personenbezogener Daten für RAG wichtig sind
Die Datenarten beeinflussen die Suche unterschiedlich stark. Pseudonymisieren Sie vor allem Werte konsistent, nach denen gesucht wird oder auf die mehrere Dokumente verweisen:
| Datenart | Einfluss auf die Suche | Empfehlung |
|---|---|---|
| Personennamen | Sehr hoch – häufigster Suchbegriff | Immer konsistent pseudonymisieren |
| Organisationen | Hoch – häufig in geschäftlich genutzten RAG-Systemen | Konsistent pseudonymisieren |
| Orte und Adressen | Mittel – abhängig vom Anwendungsfall | Stadt und Land konsistent pseudonymisieren; Straßenadressen entfernen |
| Kennungen (Konto, Krankenakte) | Hoch – Suchfragen mit exakter Übereinstimmung | Immer konsistent behandeln; die Suche nach Kennungen erfordert exakte Übereinstimmung |
| Datumsangaben | Gering bis mittel – relative Zeitangaben sind wichtig | Konkrete Daten entfernen; relative Zeitangaben erhalten |
| E-Mail-Adressen und Telefonnummern | Gering – danach wird selten gesucht | Vollständig entfernen; für die Suche nicht erforderlich |
Der Entschlüsselungsschritt: ursprüngliche Werte nach der Suche wiederherstellen
Wenn die RAG-Pipeline eine Antwort mit pseudonymisierten Token zurückgibt, müssen Sie vor der Anzeige die ursprünglichen Werte wiederherstellen. Das ist der Schritt zum Rückgängigmachen der Pseudonymisierung:
// Werkzeug: anonym_legal_detokenize_text
{
"text": "<PERSON_1> placed order #<ID_1> on <DATE_1>.",
"session_id": "<session_id aus der Antwort von anonymize_text>"
}
// Gibt den Text mit den ursprünglichen Werten zurück,
// solange die Sitzung nicht abgelaufen ist.Diesen Schritt sollten nur berechtigte Personen ausführen können. Setzen Sie eine rollenbasierte Zugriffskontrolle um: Analysten können den pseudonymisierten Index abfragen. Nur berechtigte Datenverantwortliche dürfen Antworten mit wiederhergestellten Werten sehen.
Compliance: Erwägungsgrund 26 der DSGVO und Artikel 10 der EU-KI-Verordnung
Erwägungsgrund 26 der DSGVO unterscheidet anonyme Informationen, die keiner identifizierten oder identifizierbaren Person zugeordnet werden können, von personenbezogenen Daten. Anonyme Informationen fallen nicht unter die DSGVO. Eine konsistente Pseudonymisierung mit getrennt gespeicherter und zugriffsgeschützter Zuordnungstabelle erfüllt diesen Maßstab nicht: Die Daten bleiben personenbezogen, weil mit der Zuordnung eine erneute Identifizierung möglich ist. Für pseudonymisierte Daten gelten aber geringere Pflichten, und die Pseudonymisierung ist nach Artikel 32 als Sicherheitsmaßnahme anerkannt.
Artikel 10 der EU-KI-Verordnung verlangt für Trainings-, Validierungs- und Testdaten von Hochrisiko-KI-Systemen geeignete Daten-Governance- und Datenverwaltungsverfahren. Dazu gehören Maßnahmen, um Verzerrungen zu erkennen und zu korrigieren sowie Relevanz und Repräsentativität sicherzustellen. Ein konsistent pseudonymisierter RAG-Dokumentbestand mit getrennt gespeicherter und zugriffsgeschützter Zuordnungstabelle kann eine technische Maßnahme sein, die solche Verfahren und den Datenschutz durch Technikgestaltung nach Artikel 25 DSGVO unterstützt. Für sich genommen stellt sie die Einhaltung keiner der beiden Vorschriften sicher.
Leistung: Wartezeit und Stapelverarbeitung
Der Aufruf eines gehosteten Dienstes fügt beim Einlesen der Dokumente eine Anfrage über das Netzwerk hinzu:
- Wartezeit der API: Sie hängt von Textlänge, Sprache und Netzwerk ab. Messen Sie sie in Ihrer eigenen Pipeline.
- Stapelverarbeitung: Die Stapel-API von anonym.legal nimmt je nach Tarif 5, 20, 50 oder 100 Texte pro Anfrage an. Einzelheiten stehen in der API-Dokumentation bei anonym.legal.
- Lokale Zwischenspeicherung: Speichern Sie die Sitzungszuordnung nach dem ersten Aufruf lokal zwischen. Bei weiteren Dokumenten rufen Sie die API nur für neue Werte auf.
- Aufwand für Vektordarstellungen: Anonymisierter Text hat etwas andere semantische Eigenschaften als der Originaltext. Verwenden Sie durchgehend dasselbe Modell für Vektordarstellungen. Mischen Sie keine Vektordarstellungen anonymisierter und nicht anonymisierter Texte.
Grenzen und ehrliche Einschränkungen
Konsistente Pseudonymisierung hat in einer RAG-Pipeline Grenzen. Weil derselbe Wert immer dasselbe Token erhält, kann jemand durch den Vergleich vieler Token aus verschiedenen Dokumenten Personen möglicherweise wieder identifizieren. Pseudonymisierte Daten bleiben nach der DSGVO personenbezogene Daten. Das Verfahren passt auch nicht zu jedem Anwendungsfall: Wenn beim Abruf der echte Wert benötigt wird, etwa um einen namentlich bekannten Kunden zu kontaktieren, ist ein gesonderter, zugriffsgeschützter Schritt zur Wiederherstellung erforderlich. Die Pseudonymisierung schützt den Index, aber nicht jede Stelle, die seine Daten anschließend nutzt.