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 LOCATION e RG como PERSON. 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
e-mail 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

Onde cada camada detecta: o motor NER pega nome e e-mail; os reconhecedores com dígito verificador pegam CPF, CNPJ e placa.

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

Anonimização por rota: a chave virtual com guardrail anonimiza antes de sair; rotas sem dado de cliente passam direto.

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.