Complemento da série sobre gateway de IA. O contexto está em Sua política de uso de IA não impede o vazamento.
Resumo
- PII é todo dado que identifica uma pessoa; para a LGPD, dado pessoal é isso e mais o que, combinado, identifica. Prompt de LLM carrega os dois o tempo todo.
- Existem quatro camadas de proteção — anonimização, pseudonimização, contrato e modelo local — e elas não competem: se empilham por rota.
- Anonimizar na fronteira é a recomendação padrão, e ninguém publica taxa de acerto. Medi o Presidio de fábrica em onze casos brasileiros: detecta 6, e não detecta CPF, CNPJ nem placa.
- Pior que não detectar: ele classifica cartão de crédito como
LOCATIONe RG comoPERSON. Tipo errado significa regra de mascaramento errada. - Três reconhecedores com validação de dígito consertam isso por +0,16 ms por chamada. Estão no repositório aberto.
1. O que é PII — e o que a LGPD chama de dado pessoal
PII (personally identifiable information) é qualquer informação que identifica uma pessoa: nome, CPF, e-mail, telefone, endereço.
A LGPD usa um conceito mais largo. Dado pessoal (art. 5º, I) é informação relacionada a pessoa identificada ou identificável — o que inclui combinações: CEP mais data de nascimento mais cargo identifica alguém mesmo sem o nome no texto. E há a categoria agravada dos dados sensíveis (saúde, biometria, origem racial, convicção religiosa), com regras mais duras.
Para quem opera sistemas com IA, a consequência prática é uma só: prompt é tratamento de dado pessoal sempre que carrega dado de cliente. Ticket de atendimento, transcrição de call, cadastro, contrato — tudo isso vira prompt em alguma automação, e a partir daí a empresa responde pelo que saiu.
2. Por que mandar prompt para um LLM é um problema de dado pessoal
Três propriedades da chamada a um modelo tornam o problema diferente de mandar dado para qualquer outro SaaS:
- O prompt é o payload inteiro. Não é um campo estruturado que você escolhe enviar; é texto livre, e texto livre carrega o que estiver no contexto — inclusive o que ninguém pretendia mandar.
- Retenção e treinamento dependem do contrato. O que o provedor guarda, por quanto tempo e se usa para treinar varia por tier — o plano gratuito costuma ter regra diferente do pago. O dado que entra em corpus de treinamento não volta.
- A chamada sai de dentro do código. Não é um funcionário decidindo colar algo num site: são agentes, scripts e automações fazendo isso milhares de vezes por dia, sem revisão humana. As três rotas estão mapeadas em Sua política de uso de IA não impede o vazamento.
Política escrita não intercepta requisição. O que intercepta é camada técnica — e é disso que o resto do post trata.
3. As quatro camadas de proteção de PII em chamadas de IA
Em ordem crescente de custo e de garantia. Elas não competem entre si — empilham, e a combinação certa varia por rota.
Anonimização na fronteira. Uma camada detecta e mascara o identificador antes de a chamada sair: CPF 529.982.247-25 vira CPF <BR_CPF>. Irreversível. É a proteção deste post, e a única das quatro cuja eficácia dá para medir em taxa de acerto.
Pseudonimização. Mesma detecção, mas a substituição é reversível: o mapa <PESSOA_1> → João fica guardado do seu lado, e a resposta do modelo é re-hidratada na volta. Necessária quando a resposta precisa citar a pessoa. Atenção: para a LGPD, dado pseudonimizado continua sendo dado pessoal — a reversibilidade mantém a obrigação.
Contrato com o provedor. Retenção zero, cláusula de não-treinamento, região de processamento. Reduz risco de verdade e depende de confiança contratual: o dado sai, você só combinou o que acontece com ele.
Modelo local. O dado não sai. É a única que transforma a garantia de contratual em técnica, e custa qualidade, hardware e operação — a régua de quando compensa está em A pergunta não é se um modelo pequeno é bom o suficiente.
4. Anonimização na prática: como o Microsoft Presidio funciona
O Microsoft Presidio é a ferramenta open source mais usada para isso: roda na sua infraestrutura, não manda nada para fora, e se encaixa no caminho da chamada.
Ele tem duas partes. O Analyzer encontra PII no texto combinando dois mecanismos — um motor de NLP (spaCy, por padrão) que reconhece entidades como nome e organização, e reconhecedores de padrão (regex mais validação) para identificadores com formato, como cartão e telefone. O Anonymizer aplica a máscara sobre o que o Analyzer encontrou: substituir, redigir, hash ou criptografar, por tipo de entidade.
Essa arquitetura importa para o que vem a seguir: a cobertura do Presidio é a soma do que o motor NER sabe e dos reconhecedores registrados. E os reconhecedores que vêm de fábrica foram escritos para documentos dos EUA, Reino Unido, Espanha e afins. Brasil não está na lista.
A recomendação "anonimize antes da chamada" é dada em todo material de compliance — sem número. Ninguém escreve quanto a ferramenta pega, o que deixa passar, nem quanto custa em latência. Então fui medir.
5. O que o Presidio de fábrica detecta em PII brasileiro
Onze casos, construídos com os formatos que aparecem em atendimento, contrato e cadastro no Brasil. Motor spaCy pt_core_news_sm, idioma português.
| caso | detectou | como classificou |
|---|---|---|
CPF formatado 529.982.247-25 |
não | — |
CPF sem máscara 52998224725 |
não | — |
CNPJ formatado 11.222.333/0001-81 |
não | — |
CNPJ sem máscara 11222333000181 |
não | — |
placa Mercosul BRA2E19 |
não | — |
telefone (54) 99251-3223 |
sim | PHONE_NUMBER |
| sim | EMAIL_ADDRESS, ORGANIZATION, URL |
|
CEP 95020-000 |
sim | LOCATION |
RG 12.345.678-9 |
sim | PERSON |
cartão 4111 1111 1111 1111 |
sim | LOCATION |
| nome próprio | sim | PERSON |
Seis de onze. E os cinco que faltam são justamente os identificadores nacionais.
O problema não é só o que ele perde
Repare nas duas linhas em negrito.
Cartão de crédito classificado como LOCATION. Se a sua política mascara CREDIT_CARD com um formato e LOCATION com outro — ou não mascara localização de jeito nenhum, o que é comum — o número do cartão sai inteiro.
RG classificado como PERSON. Mesma coisa: a regra que você escreveu para nome de pessoa vai ser aplicada a um número de documento.
Detecção com tipo errado é pior que não detecção, porque não aparece no relatório como falha. O contador de PII detectado sobe, o dado sai mesmo assim, e ninguém procura.
6. Como detectar CPF e CNPJ: os reconhecedores que faltam
CPF e CNPJ têm dígito verificador. Isso importa: um reconhecedor que só casa "onze dígitos" acusa número de pedido, código de rastreio e identificador interno. Com validação de dígito, ele só acusa o que é.
class CPFRecognizer(PatternRecognizer):
PATTERNS = [
Pattern("CPF mascarado", r"\b\d{3}\.\d{3}\.\d{3}-\d{2}\b", 0.6),
Pattern("CPF cru", r"\b\d{11}\b", 0.3),
]
CONTEXT = ["cpf", "documento", "contribuinte", "titular"]
def validate_result(self, texto):
n = "".join(c for c in texto if c.isdigit())
return _dv_cpf(n) if len(n) == 11 else False
Dois detalhes de desenho valem explicação.
A confiança do padrão sem máscara é mais baixa — 0,3 contra 0,6. Onze dígitos soltos são ambíguos; com a máscara, quase nunca. O CONTEXT recupera a diferença: se a palavra "CPF" aparece perto, a confiança sobe.
O validate_result é o que evita o falso positivo. Sem ele, todo número de onze dígitos vira PII, e aí o time desliga a anonimização inteira porque ela atrapalha mais do que ajuda.
O mesmo para CNPJ, e um terceiro para placa nos dois formatos — Mercosul e o antigo.
O que muda depois
| caso | antes | depois |
|---|---|---|
| CPF formatado | não | BR_CPF |
| CPF sem máscara | não | BR_CPF |
| CNPJ formatado | não | BR_CNPJ |
| CNPJ sem máscara | não | BR_CNPJ |
| placa Mercosul | não | BR_PLACA |
111.111.111-11 (inválido) |
não | não — dígito rejeita |
52998224726 (não é CPF) |
não | não — dígito rejeita |
As duas últimas linhas são o ponto. Detectar CPF é fácil; detectar CPF sem acusar todo número de onze dígitos é o que faz alguém deixar a anonimização ligada.
7. Quanto custa anonimizar: a latência medida
Essa é a parte que decide onde a anonimização entra no caminho.
| medição | latência |
|---|---|
| texto curto (~55 caracteres), Presidio de fábrica | 4,48 ms |
| texto curto, com os três reconhecedores | 4,64 ms |
| texto longo (~3.240 caracteres), Presidio de fábrica | 89,6 ms |
Os três reconhecedores custam 0,16 ms — a diferença entre as duas primeiras linhas. São regex mais uma validação aritmética; o custo é irrelevante perto do resto, e por isso o texto longo só foi medido de fábrica.
O que custa é o Presidio em si, e ele escala com o tamanho do texto: 4,5 ms num trecho curto, quase 90 ms num texto de três mil caracteres. Isso é análise de linguagem natural, não casamento de padrão.
E aí está a implicação prática. No post sobre o overhead do gateway eu medi cerca de 10 ms de camada. Somar anonimização num prompt longo pode adicionar quase dez vezes isso, e passa a ser o item mais caro do caminho antes do modelo.
Duas consequências:
- Anonimize a rota, não tudo. Ligue no que carrega dado de cliente; deixe fora do resto. No gateway isso é uma linha por alias.
- Meça no seu tamanho de prompt. 90 ms veio de três mil caracteres. Se o seu prompt tem vinte mil, o número é outro.
Condições da medição: máquina de desenvolvimento Linux, spaCy pt_core_news_sm, 200 execuções para o texto curto e 50 para o longo, uma rodada. Ordem de grandeza, não medição citável.
8. O que mais dá para plugar no Presidio
Os três reconhecedores fecham CPF, CNPJ e placa. Sobram duas frentes: os documentos que eu não cobri, e o motor NER que classifica cartão como LOCATION. As duas se resolvem sem trocar de ferramenta.
Mais documentos, sem escrever a aritmética: validate-docbr. Pacote Python que valida CNH, CNS, PIS, título de eleitor e RENAVAM, além de CPF e CNPJ — tudo com dígito verificador. O encaixe é o mesmo da seção 6: um PatternRecognizer por documento, com o validate_result delegando para o pacote em vez da conta manual.
Um motor maior no mesmo lugar: pt_core_news_lg. A medição rodou com o pt_core_news_sm, o menor modelo de português do spaCy. O grande carrega 500 mil vetores de palavra e tende a errar menos em nome e organização. A troca é uma linha de configuração — e vale rodar os mesmos onze casos antes e depois, porque modelo maior não é garantia de acerto no seu texto.
Trocar o motor por um transformer: TransformersNlpEngine. O Presidio aceita qualquer modelo de classificação de tokens do Hugging Face como motor NER; a configuração só mapeia os rótulos do modelo para os tipos do Presidio. Em português existe o ner-bert-base-cased-pt-lenerbr, um BERTimbau ajustado para NER com F1 de 0,89 — no LeNER-Br, que é texto jurídico. Dois poréns: fora do domínio jurídico esse número cai, e transformer custa latência exatamente na parte que já escala com o tamanho do texto (seção 7).
A régua de decisão: identificador com formato se resolve com regex e dígito verificador — barato e determinístico. Motor NER maior, só se nome e organização estiverem vazando. Transformer, só com os números da seção 7 medidos de novo, porque ele muda a ordem de grandeza do custo.
9. Onde a anonimização entra na arquitetura
No gateway, como guardrail em modo pre_call, ligado por chave virtual. A aplicação não muda; a rota que precisa de anonimização recebe uma chave que a tem, e as outras não. O desenho completo da camada está em Um gateway de IA em 40 linhas de YAML.
E o limite honesto: anonimização remove identificador. Funciona para dado pessoal — CPF, e-mail, telefone, nome. Não resolve segredo industrial: não existe como anonimizar a lógica de um algoritmo proprietário sem destruir a pergunta que você está fazendo ao modelo. Se o problema é esse, a resposta é modelo local, não redação.
Os três reconhecedores estão em redaction/ no repositório aberto, junto com o script de diagnóstico e o stack do gateway.
Antes de ligar em qualquer lugar, rode nos seus dados. Onze casos construídos medem cobertura de formato, não recall em texto real de produção — e o seu domínio tem formato que o meu não tem.
Perguntas frequentes sobre PII e LLMs
Anonimizar o prompt atende a LGPD? Dado anonimizado de forma irreversível deixa de ser considerado dado pessoal (art. 12 da LGPD). Mascaramento na fronteira reduz a exposição de forma mensurável; se a substituição for reversível (pseudonimização), o dado continua pessoal e as obrigações continuam valendo. Isto é engenharia, não parecer jurídico — a base legal do tratamento continua sendo assunto do seu jurídico.
Posso mandar CPF para um modelo de IA? Tecnicamente, nada impede. Juridicamente, é tratamento de dado pessoal: exige base legal, e o provedor do modelo entra na cadeia como operador. Na prática, as opções seguras são mascarar antes de sair ou processar em modelo local.
Qual a diferença entre anonimização e pseudonimização?
Anonimização é irreversível: <BR_CPF> não volta a ser o CPF. Pseudonimização troca por um marcador reversível com o mapa guardado do seu lado — útil quando a resposta precisa referenciar a pessoa, mas mantém o dado como pessoal perante a LGPD. O Anonymizer do Presidio faz os dois, por tipo de entidade.
O Presidio funciona em português? Funciona, com motor spaCy em português — mas os reconhecedores de documentos brasileiros não vêm de fábrica. Sem eles, CPF, CNPJ e placa passam batido, como a medição acima mostra. Com os três reconhecedores registrados, a cobertura fecha por +0,16 ms por chamada.
Como ajudamos times a adotar IA
Trabalhamos com times de engenharia que buscam incorporar IA ao dia a dia de desenvolvimento — não como experimento, mas como parte real do fluxo de trabalho.
Isso passa por escolher as ferramentas certas para o contexto do time, configurá-las de forma que façam sentido para a política de dados da empresa e garantir que os desenvolvedores saibam usá-las de um jeito que realmente aumente a produtividade, em vez de gerar mais fricção.
Se você tem um time de desenvolvimento e está tentando colocar IA para trabalhar de forma séria, fale com a gente.
