Dé-identifier et restaurer un texte
Vous avez un texte contenant des données confidentielles et vous voulez le dé-identifier, l'envoyer à un LLM, puis restaurer les valeurs d'origine dans la réponse. Ce guide fait l'aller-retour avec le seul cœur de piighost, sans modèle ni dépendance optionnelle. Les motifs du détecteur viennent du catalogue piighost. Ils sont récupérés à chaque construction du détecteur, ce qui demande un accès réseau.
Installez le cœur.
uv add piighostpip install piighostFaire l'aller-retour
Un pipeline enchaîne un détecteur, un linker et un anonymiseur. Seul le détecteur est obligatoire. Le linker vaut par défaut ExactEntityLinker et l'anonymiseur Anonymizer(LabelCounterPlaceholderFactory()). anonymize renvoie le texte dé-identifié et le jeton attribué à chaque entité. deanonymize rejoue cette correspondance en sens inverse.
import asyncio
from piighost.components.detector import RegexDetector
from piighost.pipeline import AnonymizationPipeline
detector = RegexDetector.from_catalog("catalog:piighost/generic")
pipeline = AnonymizationPipeline(detector)
async def main() -> None:
result = await pipeline.anonymize("Contact alice@example.com from 192.168.1.42.")
print(result.text)
restored = pipeline.deanonymize(result.text, result.tokens)
print(restored)
asyncio.run(main())La sortie doit être :
Contact <<EMAIL:1>> from <<IPV4:1>>.
Contact alice@example.com from 192.168.1.42.result.text porte <<EMAIL:1>> à la place de alice@example.com. result.tokens associe chaque entité à son jeton. Passez-le tel quel à deanonymize pour retrouver le texte d'origine.
Restaurer une réponse du LLM
deanonymize restaure n'importe quel texte portant les jetons, pas seulement celui que le pipeline a produit. Si le LLM répond avec <<EMAIL:1>>, réinjectez les vraies valeurs avec la même correspondance result.tokens.
async def main() -> None:
result = await pipeline.anonymize("Contact alice@example.com from 192.168.1.42.")
llm_reply = "I sent the message to <<EMAIL:1>>."
print(pipeline.deanonymize(llm_reply, result.tokens))
asyncio.run(main())La sortie doit être :
I sent the message to alice@example.com.Regrouper les occurrences répétées
Une même valeur citée plusieurs fois reçoit un seul jeton, donc le LLM garde le fil. ExactEntityLinker regroupe les occurrences par valeur et par label.
from piighost.components.detector import ExactMatchDetector
detector = ExactMatchDetector({"Patrick": "PERSON", "Paris": "LOCATION"})
pipeline = AnonymizationPipeline(detector)
async def main() -> None:
result = await pipeline.anonymize("Patrick habite à Paris. Patrick aime Paris.")
print(result.text)
asyncio.run(main())La sortie doit être :
<<PERSON:1>> habite à <<LOCATION:1>>. <<PERSON:1>> aime <<LOCATION:1>>.ExactMatchDetector détecte des valeurs littérales fixées. L'exemple reste ainsi reproductible sans charger de modèle. Pour du texte libre, remplacez-le par un détecteur NER (reconnaissance d'entités nommées) ou LLM, voir la référence des détecteurs.
Changer la forme des jetons
LabelCounterPlaceholderFactory, la factory par défaut, produit <<LABEL:N>>. Si vous voulez une autre forme de jeton, passez au pipeline un Anonymizer construit sur une autre factory. Ici, LabelHashPlaceholderFactory remplace le numéro par une empreinte courte.
import asyncio
from piighost.components.anonymizer import Anonymizer
from piighost.components.detector import ExactMatchDetector
from piighost.components.placeholder import LabelHashPlaceholderFactory
from piighost.pipeline import AnonymizationPipeline
detector = ExactMatchDetector({"Patrick": "PERSON", "Marie": "PERSON"})
anonymizer = Anonymizer(LabelHashPlaceholderFactory())
pipeline = AnonymizationPipeline(detector, anonymizer=anonymizer)
async def main() -> None:
result = await pipeline.anonymize("Patrick, Marie, Patrick.")
print(result.text)
asyncio.run(main())La sortie doit être :
<<PERSON:09ef3b74>>, <<PERSON:c4912b76>>, <<PERSON:09ef3b74>>.L'empreinte est calculée à partir du label et du rang de l'entité, jamais à partir de la valeur. Patrick garde donc le même jeton à ses deux apparitions, et Marie en reçoit un autre.
Pour restaurer les valeurs, la factory doit préserver l'identité, c'est-à-dire donner un jeton distinct à chaque valeur. LabelCounterPlaceholderFactory le fait. LabelPlaceholderFactory ne le fait pas, parce qu'elle donne le même <<PERSON>> à deux personnes distinctes. Voir la page Fabriques de placeholders.
Voir aussi
- Détecteurs prêts à l'emploi pour combiner groupes du catalogue et détecteurs.
- Référence du pipeline pour les étages optionnels.
- Étendre piighost pour écrire vos propres composants.