Como usar o laya para detectar phishing, spam e risco de churn em texto, email e ticket?

O laya é um modelo de decisão aberto da Convai Innovations que responde perguntas tipadas sobre um estado (texto, email, ticket ou documento JSON) em uma única passagem para frente. Para moderação, você troca regex e listas de bloqueio por perguntas: noul devolve P(true) calibrado de 0.0 a 1.0 para phishing, spam, jailbreak e risco de churn, e score posiciona severidade numa régua ordinal. Instala com pip install laya, carrega os pesos do Hugging Face e roda local sob Apache 2.0. Atenção: os números altos (99,3% em spam Enron, 98% em phishing) vêm de fine-tuning, não do checkpoint base zero-shot
Fala aí, beleza? Se o teu time ainda mantém uma planilha de regex pra pegar phishing e uma lista de domínios bloqueados que cresce toda semana, esse post é pra você
Todo mundo que já cuidou de moderação conhece a dor: a regra pega a maior parte dos casos, aí o atacante troca uma letra, mete um zero no lugar do "o", e você volta pro editor pra remendar o padrão
A proposta aqui é diferente: em vez de descrever o formato do ataque, você faz uma PERGUNTA sobre o conteúdo e recebe uma probabilidade calibrada de volta
É isso que o laya faz. Ele é um modelo de decisão aberto (open-weights) publicado pela Convai Innovations, do tipo System 1, não autoregressivo, que avalia perguntas tipadas sobre um estado (texto, email, ticket ou documento JSON) em um único forward pass
Sem prompt gigante, sem esperar token por token sair. Você manda o estado e um dicionário de perguntas, ele responde tudo de uma vez 🙂
O que você precisa antes de começar
A lista é curta, e isso já é um bom sinal
- Python com pip funcionando, porque o pacote vive no PyPI
- Acesso ao Hugging Face, já que os pesos são baixados de lá pelo próprio pacote
- GPU é opcional, mas muda o jogo em volume: a latência declarada é de 33 ms para uma pergunta e 7,2 ms por pergunta em lote, medida em GPU T4
- Decidir qual checkpoint usar: o principal em inglês usa ModernBERT-large como backbone e tem cerca de 421 milhões de parâmetros, e existe um checkpoint multilíngue cobrindo mais de 100 idiomas
Formação Claude Code
Domine Claude Code do absoluto zero até o avançado
- 120 aulas
- 4 projetos
- 9h 45min
Sobre licença e onde o modelo roda: os pesos são distribuídos sob Apache 2.0 e a execução é local
Isso importa MUITO pro caso de moderação. Você está jogando email de cliente e corpo de ticket dentro do modelo, e esse dado não precisa sair da tua infra
Uma observação honesta antes de seguir: se o teu corpus é 100% português, o checkpoint multilíngue é o caminho natural, porém não existe métrica pública por idioma pra PT-BR. Então você vai ter que medir no teu próprio dado, e eu volto nisso lá na frente
As três primitivas: quando usar choice, score e noul
Antes de escrever qualquer linha de código, para e mapeia. O laya tem três primitivas de pergunta, e escolher a errada é o jeito mais rápido de achar que a ferramenta é ruim
choice: escolher uma opção de um conjunto definido
É a classificação clássica. Categoria do ticket, tipo de solicitação, motivo do contato
Regra de ouro da própria documentação: mantenha abaixo de ~20 opções por pergunta
E aqui entra o porquê, que é a parte interessante. As opções dividem um orçamento fixo de 256 tokens no head compartilhado, então quanto mais rótulos você empilha, menos espaço cada um tem, e a acurácia cai
Se você conhece aquele problema de menu com opção demais onde o usuário não acha nada, é o mesmo espírito: mais opções não é mais poder
score: régua ordinal pra ordenar, não pra decidir
O score posiciona o estado numa régua de níveis (0, 1, 2…). A doc cita exatamente os casos que interessam pra moderação: urgência, frustração e severidade
É a primitiva perfeita pra responder "quão grave é esse dano?" em vez de "é grave, sim ou não?"
Guarda essa: a própria documentação diz que score é a primitiva mais fraca do modelo. Volto nisso na seção de limiares
noul: booleana com probabilidade calibrada
Essa é a estrela do post. O noul é booleano e devolve P(true) calibrado de 0.0 a 1.0
E olha os exemplos que a documentação do laya lista pra essa primitiva: phishing, spam, jailbreak e risco de churn
Ou seja, phishing, spam e risco de churn já vêm previstos pelo desenho da ferramenta
É exatamente esse trio que eu vou montar como noul no exemplo, somado a uma régua de severidade com score, que é a primitiva certa pra graduar gravidade
Mapeamento rápido antes do código:
| Sua regra manual hoje | Primitiva certa |
|---|---|
| Regex de domínio falso e link encurtado | noul (phishing) |
| Lista de palavras bloqueadas no corpo do email | noul (spam) |
| "Ticket com palavrão vai pro supervisor" | score (severidade, 0 a 3) |
| "Cliente falou em cancelar" | noul (churn risk) |
| Tag de assunto do ticket | choice |
Passo a passo: da regra manual à pergunta tipada
Bora ver na prática?
- Instalar o pacote
pip install laya
O erro comum deste passo: tentar procurar um binário ou um servidor pra subir. Não tem. É biblioteca Python, o modelo roda dentro do teu processo
- Carregar os pesos do checkpoint
import laya
# checkpoint em inglês
agent = laya.load("convaiinnovations/laya")
# ou o multilíngue
# agent = laya.load("convaiinnovations/laya", subfolder="multilingual")
O erro comum deste passo: esquecer o subfolder="multilingual" e ficar achando que o modelo é ruim em português quando na verdade você carregou o checkpoint em inglês
- Preparar o state
O estado é o que você quer avaliar: o corpo do email, o texto do ticket ou um documento JSON
state = """
De: [email protected]
Assunto: Sua conta sera suspensa em 24h
Prezado cliente, detectamos atividade irregular.
Confirme seus dados agora clicando no link abaixo
para evitar o bloqueio permanente da sua conta.
"""
O erro comum deste passo: mandar só o assunto do email. Cabeçalho, remetente e corpo juntos dão MUITO mais contexto pro modelo do que um pedaço solto
- Escrever o dicionário de perguntas
Cada pergunta declara seu type, suas instructions e, quando se aplica, seus criteria
questions = {
"is_phishing": {
"type": "noul",
"instructions": "Esta mensagem tenta enganar o destinatario para obter credenciais, dados bancarios ou acesso a conta?"
},
"is_spam": {
"type": "noul",
"instructions": "Esta mensagem e comercial nao solicitada ou envio em massa sem relacao previa?"
},
"harm_severity": {
"type": "score",
"instructions": "Avalie a severidade do dano potencial ao destinatario",
"criteria": {
"0": "Nenhum dano, mensagem legitima",
"1": "Incomodo, propaganda inofensiva",
"2": "Risco moderado, pede dados nao sensiveis",
"3": "Risco alto, pede credencial, pagamento ou acesso"
}
},
"churn_risk": {
"type": "noul",
"instructions": "O autor demonstra intencao de cancelar, migrar para concorrente ou encerrar o contrato?"
}
}
O erro comum deste passo: escrever instructions vago tipo "isso é ruim?". A pergunta tipada é o teu prompt, e pergunta preguiçosa devolve decisão preguiçosa
Outro cuidado: nos criteria do score, descreva o que caracteriza CADA nível. Nível sem descrição vira chute
- Rodar tudo em uma única passagem
result = agent.predict(state, questions)
print(result)
Aqui mora a graça da coisa. As quatro perguntas são respondidas em um único forward pass, não são quatro chamadas
É por isso que o custo em lote cai pra 7,2 ms por pergunta: você paga a leitura do estado uma vez e pendura várias decisões nela
O erro comum deste passo: montar um loop chamando predict uma vez por pergunta. Funciona, mas você jogou fora exatamente a vantagem do modelo
- Definir limiares a partir da probabilidade, não do booleano cru
O noul te dá um número de 0.0 a 1.0. Se você transformar isso em True/False na primeira linha do teu código, você acabou de jogar fora a informação mais útil que o modelo produziu
O erro comum deste passo é justamente esse: tratar 0.51 e 0.99 como a mesma coisa
Como ler as probabilidades e definir limiares de bloqueio
Um corte único ("acima de 0.5 bloqueia") é o jeito mais rápido de gerar falso positivo em cliente legítimo e phishing passando batido
O desenho que faz sentido pra moderação é por FAIXA:
- Faixa alta: bloqueia e registra
- Faixa do meio: manda pra revisão humana
- Faixa baixa: libera
p = result["is_phishing"]
sev = result["harm_severity"]
if p >= 0.9 and sev >= 2:
acao = "bloquear"
elif p >= 0.6:
acao = "revisar"
else:
acao = "liberar"
Repara que eu combinei as duas primitivas: o noul diz SE é phishing, e o score diz QUÃO grave seria se fosse
Um phishing com probabilidade alta e severidade 3 fura a fila. Um com probabilidade alta e severidade 1 pode esperar o analista acordar
E por que essa combinação e não score sozinho decidindo? Porque a própria documentação do laya diz que score é a primitiva mais fraca, reportando 0,282 no SST-5
Tome cuidado com isso. Use score pra ORDENAR fila, nunca pra decidir bloqueio sozinho
Já o noul tem um argumento forte a favor: em filtragem de spam de email no dataset Enron o modelo reporta 99,3% de acurácia com erro de calibração de 0,013, e em detecção de phishing reporta 98% de acurácia
Erro de calibração baixo é o que dá licença pra você confiar na faixa. Significa que a probabilidade devolvida acompanha a frequência real de acerto, e não é "0.8 porque sim"
(Guarda esse asterisco: esses números vêm de fine-tuning, e eu detono esse ponto na seção do veredito)
No caso de churn a lógica é a mesma, só muda o destino da decisão: em vez de bloquear, você dispara alerta. Se o teu time já tem automações de alerta de risco de churn rodando, o noul entra como o gatilho que decide quando o fluxo começa, substituindo aquele filtro de palavra-chave tipo "cancelar"
Regras manuais x perguntas tipadas com o laya
Comparação por natureza da coisa, sem inventar métrica pro lado das regras manuais (que é diferente em cada empresa)
| Critério | Regex e listas de bloqueio | Perguntas tipadas com o laya |
|---|---|---|
| Esforço de manutenção | Cresce a cada variação nova de ataque | Reescrever a pergunta, não o padrão |
| Cobertura de variações | Só pega o que o padrão descreve | Avalia o conteúdo, não o formato |
| Confiança da decisão | Booleano cru, bateu ou não bateu | P(true) calibrado de 0.0 a 1.0 |
| Múltiplas decisões no mesmo item | Uma passada por regra | Várias perguntas em um único forward pass |
| Latência | Depende do tamanho do conjunto de regras | 33 ms para uma pergunta, 7,2 ms por pergunta em lote (T4) |
| Custo e privacidade | Roda na tua infra | Pesos Apache 2.0, execução local |
| Dependência de dado rotulado | Nenhuma, você escreve a regra | Alta, os números bons vêm de fine-tuning |
| Explicabilidade | Você sabe exatamente qual regra bateu | Você sabe a probabilidade, não a causa |
As duas últimas linhas são as honestas. Regex tem uma virtude que modelo nenhum entrega: quando bloqueia, você aponta o dedo pra linha exata
Vale trocar suas regras manuais pelo laya?
Agora a parte que ninguém gosta de escrever no post de lançamento
Aqueles 99,3% em spam Enron e 98% em phishing são resultado de fine-tuning. Não é o que você recebe abrindo o pacote e rodando o checkpoint base
E a própria documentação é transparente sobre isso, o que eu acho muito massa. No benchmark typed-decisions, os checkpoints base ficam em 0,362 e 0,352 zero-shot, contra um baseline aleatório de 0,318
Lê de novo: zero-shot, o modelo base está quase em cima do aleatório nesse benchmark
Com fine-tuning, o checkpoint sobe pra 0,766 no mesmo benchmark. A diferença entre "quase sorteio" e "ferramenta de produção" é o treino com dado teu
Soma a isso os dois pontos fracos já conhecidos:
scoreé a primitiva mais fraca (0,282 no SST-5)- idiomas de baixo recurso vão mal: Suaíli 0,210, Tâmil 0,250, Amárico 0,110
Então, pra quem faz sentido?
Faz sentido se você já tem histórico rotulado (emails marcados como spam, tickets marcados como churn, casos de phishing confirmados), tem alguém que sabe rodar um treino e quer processar volume alto com privacidade e sem pagar por chamada
Não faz sentido se você quer plugar hoje, sem dado nenhum, e aposentar o teu antispam amanhã de manhã. Nesse cenário você vai trocar uma regra chata mas previsível por uma probabilidade não calibrada pro teu domínio, e isso é pior
O caminho sensato é o do meio: roda o checkpoint em paralelo com as regras atuais, em modo sombra, e compara. Deixa o laya opinar sem poder de bloqueio por umas semanas
Fine-tuning: o caminho para os números que a doc cita
Se a conclusão acima te convenceu, o próximo passo é treinar
O repositório oficial fica em github.com/NandhaKishorM/laya, mantido por NandhaKishorM (Nandakishor, da Convai Innovations), e foi publicado em 18 de setembro de 2026
Sim, é coisa nova. Trata como tal
Lá dentro tem um notebook de fine-tuning para o benchmark typed-decisions preparado pra rodar em 2x T4 no Kaggle:
notebooks/laya_finetune_typed_decisions_2xT4_kaggle.ipynb
A escolha de 2x T4 no Kaggle é generosa com quem não tem PC da Nasa em casa: dá pra reproduzir o fluxo sem montar infra própria só pra descobrir se a ideia presta
Não vou te passar receita de hiperparâmetro aqui, porque não existe número oficial publicado fora do notebook e eu não vou chutar. Abre o notebook, roda o caminho que está ali com o teu dataset, e depois ajusta
O que vale reforçar: o formato do teu dado de treino tem que ser o mesmo do que você vai usar em produção. Se em produção o estado é um JSON de ticket com campos de cliente, treina com JSON de ticket, não com texto solto
Conclusão
O fluxo pra sair das regras manuais é sempre o mesmo, e a ordem importa:
- Mapeia cada regra atual pra primitiva certa (
noulpra sim/não,scorepra gravidade,choicepra categoria) - Escreve as perguntas com
instructionsespecífica ecriteriadescrito - Roda tudo num único
agent.predictem vez de uma chamada por pergunta - Mede no TEU dado, em modo sombra, comparando com o que as regras já entregam
- Calibra as faixas de bloquear, revisar e liberar a partir da probabilidade
- Só então aposenta a regra, uma de cada vez
Teu próximo passo concreto é bem chato e bem eficaz: pega um lote de emails e tickets que o teu time JÁ rotulou internamente, roda o checkpoint neles e olha a distribuição das probabilidades
Se os casos confirmados de phishing ficarem agrupados lá em cima e os legítimos lá embaixo, você tem sinal e pode pensar em fine-tuning
Se estiver tudo embolado no meio, você acabou de economizar semanas antes de treinar qualquer coisa 🙂
Até o próximo post!
Perguntas frequentes
O laya precisa de internet pra rodar em produção depois de instalado?
Os pesos vêm do Hugging Face na hora do laya.load(), mas depois disso a execução é local. Isso importa justamente pro caso de moderação, porque email e ticket de cliente não precisam sair da tua infra.
Dá pra usar o laya em português pra detectar phishing e spam?
Existe um checkpoint multilíngue cobrindo mais de 100 idiomas, carregado com subfolder="multilingual". Só que não há métrica pública por idioma pra PT-BR, então o certo é medir acurácia e calibração no teu próprio corpus antes de confiar cegamente.
Qual a diferença entre usar noul e score pra risco de churn?
A documentação lista churn risk como exemplo de noul, que devolve uma probabilidade calibrada de 0.0 a 1.0 pra uma pergunta booleana tipo "esse cliente vai cancelar?". Já o score serve pra ordenar intensidade, como severidade ou frustração, não pra decidir sim ou não.
O laya é rápido o suficiente pra rodar em fila de ticket em tempo real?
A latência declarada em GPU T4 é de 33 ms pra uma pergunta única e 7,2 ms por pergunta quando roda em lote. Pra volume alto de ticket, processar em batch é o que faz a conta fechar.
Os números de acurácia em spam e phishing valem pra qualquer checkpoint do laya?
Não, esses números são resultado de fine-tuning, como eu mostro na seção do veredito. O checkpoint base fica bem abaixo disso, então a diferença entre modelo cru e modelo ajustado com o teu dado é enorme.
Por que a primitiva score não é recomendada pra decisão crítica de moderação?
A própria documentação do laya aponta que score é a primitiva mais fraca do modelo. Por isso ela funciona melhor pra ordenar urgência ou severidade numa régua do que pra ser a única base de uma decisão automática de bloqueio.
Formações
Formação Vibe Coding
Do Prompt ao Produto: Crie Software Real com IA
- 474 aulas
- 20 projetos
- 39h 27min
Blog | Mais populares

Como fazer triagem de tickets de suporte com o laya: urgência, frustração e departamento
Triagem de tickets com laya: urgência, frustração e departamento em um forward pass, sem JSON. Veja instalação, código e a ressalva do zero-shot.

Choice, score e noul: quais são os tipos de pergunta do Laya e quando usar cada um?
Entenda os tipos de pergunta do Laya: choice, score e noul. Como cada um funciona, a acurácia de cada primitiva e quando usar em cada situação.

Confidence gating no laya: como desenhar o fallback quando a decisão não é confiável?
Confidence gating laya: como calibrar o corte de probabilidade e desenhar o fallback quando a decisão do modelo não é confiável.
