Aller au contenu

Migrer depuis PresidioReversibleAnonymizer

Pour migrer depuis PresidioReversibleAnonymizer, enveloppez votre AnalyzerEngine Presidio dans un PresidioDetector et construisez un ThreadAnonymizationPipeline dessus. Appelez ensuite les méthodes anonymize et deanonymize du pipeline avec un thread_id. Presidio continue de détecter les valeurs, et piighost les remplace puis les restaure.

L'ancienne classe faisait partie de langchain-experimental, que LangChain a abandonné le 22 mai 2026. Son dépôt est archivé, elle ne recevra donc plus de correctif.

Avant, avec PresidioReversibleAnonymizer

L'ancienne classe détecte avec Presidio, remplace chaque valeur par une fausse valeur tirée de Faker, et garde la correspondance dans l'objet.

from langchain.chat_models import init_chat_model
from langchain_experimental.data_anonymizer import PresidioReversibleAnonymizer

anonymizer = PresidioReversibleAnonymizer(analyzed_fields=["PERSON", "EMAIL_ADDRESS"])
model = init_chat_model("openai:gpt-5.6-terra")

safe_text = anonymizer.anonymize("Patrick Martin wrote from patrick@example.com.")
reply = model.invoke(safe_text)
print(anonymizer.deanonymize(reply.content))

anonymizer.save_deanonymizer_mapping("mapping.json")

Le LLM lit un nom inventé et un email inventé à la place de Patrick Martin et patrick@example.com. deanonymize() remet les vraies valeurs, et save_deanonymizer_mapping() écrit la correspondance dans un fichier JSON si vous voulez la garder.

Après, avec piighost

Le même aller-retour avec piighost garde le moteur Presidio et remplace l'objet de l'ancienne classe par un pipeline conversationnel.

import asyncio

from langchain.chat_models import init_chat_model
from presidio_analyzer import AnalyzerEngine

from piighost.components.detector.ner import PresidioDetector
from piighost.pipeline import ThreadAnonymizationPipeline

detector = PresidioDetector(
    AnalyzerEngine(), labels={"PERSON": "PERSON", "EMAIL": "EMAIL_ADDRESS"}
)
pipeline = ThreadAnonymizationPipeline(detector)
model = init_chat_model("openai:gpt-5.6-terra")


async def main() -> None:
    safe = await pipeline.anonymize(
        "Patrick Martin wrote from patrick@example.com.", thread_id="thread-42"
    )
    print(safe.text)

    reply = await model.ainvoke(safe.text)
    print(await pipeline.deanonymize(reply.content, thread_id="thread-42"))


asyncio.run(main())

La sortie doit être :

<<PERSON:1>> wrote from <<EMAIL:1>>.
Thank you Patrick Martin, I will write to patrick@example.com.

Le LLM lit <<PERSON:1>> et <<EMAIL:1>>. Le dictionnaire labels renomme le type EMAIL_ADDRESS de Presidio en EMAIL. Il joue aussi le rôle de analyzed_fields, puisqu'un type qu'il ne liste pas est écarté. La mémoire de conversation garde la correspondance sous thread-42, donc le message suivant du fil reprend les mêmes placeholders.

Dans un agent LangChain

Si l'ancienne classe était placée dans une chaîne LangChain devant un agent, donnez le même pipeline à PIIAnonymizationMiddleware au lieu de l'appeler à la main. Le middleware dé-identifie chaque message, restaure la réponse et, par défaut, donne les vraies valeurs aux outils. Voir Middleware LangChain.

Ce qui change

  • Des placeholders remplacent les fausses valeurs. <<PERSON:1>> ne peut pas se confondre avec un vrai nom, alors qu'un nom tiré de Faker le peut. Une factory Faker est écartée exprès, voir la FAQ.
  • La correspondance est propre à une conversation. Un ancien objet gardait une seule correspondance pour tous les textes qu'il voyait, alors que le pipeline en garde une par thread_id et l'efface avec forget_thread.
  • La correspondance est stockée dans une mémoire de conversation, en RAM par défaut, ou dans Redis ou en SQL, qui peuvent chiffrer les valeurs. Elle remplace save_deanonymizer_mapping() et load_deanonymizer_mapping(). Voir Déploiement.
  • Les méthodes sont asynchrones, il faut donc les attendre avec await.
  • La détection s'ouvre à d'autres détecteurs. Presidio peut tourner à côté d'un groupe regex du catalogue ou d'un modèle GLiNER2, voir Détecteurs prêts à l'emploi.
  • L'argument allow_list de anonymize() devient une liste à laisser en clair dans le pipeline, voir Masquer ou laisser en clair.
  • Le middleware LangChain restaure aussi les arguments des appels d'outils et une réponse en flux, ce que l'ancienne classe ne faisait pas.