Como fazer triagem de tickets de suporte com o laya: urgência, frustração e departamento

Triagem de tickets com laya funciona assim: em vez de pedir JSON pra uma LLM, você declara perguntas tipadas e o modelo devolve respostas tipadas com probabilidade em um único forward pass, sem gerar texto. Departamento vira choice, urgência e frustração viram score ordinal, pedido de reembolso vira noul. Instala com pip install laya (Python 3.10+), carrega um checkpoint e roda agent.predict(state, questions). Pesos Apache 2.0, roda local, 33 ms por pergunta em T4. A ressalva: os checkpoints base ficam perto do acaso em zero-shot no benchmark typed-decisions, então o ganho real vem de especializar com seus tickets
Fila de suporte lotada, e a ideia genial é jogar o texto do chamado numa LLM pedindo "responda em JSON com departamento, urgência e frustração"
Aí vem a vírgula solta, a crase no lugar errado, o json.loads explodindo e, o clássico dos clássicos, o modelo inventando um departamento chamado "suporte premium" que nunca existiu no seu sistema 😛
O laya resolve isso por um caminho diferente
Ele é um modelo de decisão System 1 não autorregressivo da Convai Innovations, anunciado em 19 de setembro de 2026, que recebe um estado (texto, e-mail, ticket ou JSON) mais perguntas tipadas e devolve respostas tipadas com probabilidades calibradas em um único forward pass
Sem gerar um token de texto sequer
Como ele nunca emite texto e só distribui probabilidade sobre um conjunto fixo de opções, resposta malformada e categoria fora do enum são impossíveis por construção
Neste post tu vai montar a triagem completa de um chamado: departamento, urgência, nível de frustração e flag de reembolso, tudo em uma chamada só
Bora?
O que você precisa antes de começar
A lista é curta, prometo
- Python 3.10 ou superior, requisito do pacote
- O pacote instalado via
pip install laya - Um checkpoint escolhido (já explico qual)
São três checkpoints, todos Apache 2.0:
- laya 421M, em inglês, sobre ModernBERT-large, contexto de 512 tokens
- laya-multilingual 322M, sobre mmBERT-base, contexto de 1024 tokens e mais de 100 idiomas
- laya-typed-decisions, ajustado no split de treino do benchmark typed-decisions
Formação Claude Code
Domine Claude Code do absoluto zero até o avançado
- 120 aulas
- 4 projetos
- 9h 45min
Se o seu suporte atende em português, o multilíngue é o caminho natural: mais idiomas e o dobro de contexto, o que importa MUITO quando o cliente escreve aquele textão de reclamação
O projeto é mantido pela Convai Innovations: os pesos vivem no Hugging Face sob a organização convaiinnovations e o repositório de código do projeto fica em NandhaKishorM/laya
E se tu quer sentir a coisa antes de instalar qualquer dependência, tem demo oficial no Hugging Face Spaces em convaiinnovations/laya-demo, com abas de triagem, e-mail, guardrails, RAG, moderação, roteamento e um playground
Cola um ticket real na aba de triagem e olha o que sai antes de escrever uma linha de código
Passo a passo: triagem de tickets com perguntas tipadas
A lógica aqui é diferente de prompt
Tu não pede pro modelo "pensar", tu declara a pergunta e o espaço de resposta, e ele pontua esse espaço
Se você conhece um formulário com campos tipados (select, range, checkbox), a analogia é essa: você define os campos, o laya preenche com probabilidade
- Instale o pacote e carregue o checkpoint
pip install laya
import laya
agent = laya.load("convaiinnovations/laya-multilingual")
O erro comum deste passo: rodar em Python 3.9 e tomar pau na instalação. O pacote exige 3.10 ou superior, confere com python --version antes de sair xingando o pip
- Monte o state a partir do chamado
O state é o que o modelo vai olhar. Pode ser texto puro, e-mail, o ticket inteiro ou um dicionário:
state = {
"subject": "Cobrança duplicada no cartão",
"body": "Já é a segunda vez que vocês cobram duas vezes. Quero meu dinheiro de volta hoje, senão eu cancelo."
}
O erro comum aqui: jogar o histórico inteiro da conversa dentro do state e estourar o contexto do checkpoint. São 512 tokens no inglês e 1024 no multilíngue, então corta o rodapé de assinatura, os "Enviado do meu iPhone" e o threading antigo
- Declare o departamento como
choice
Cada pergunta é um dicionário com type, instructions e criteria. Este é o exemplo oficial de roteamento:
questions = {
"department": {
"type": "choice",
"instructions": "Which team should handle `body`?",
"criteria": {
"billing": "invoices, payments, refunds",
"technical": "bugs and outages",
"sales": "pricing"
}
}
}
Repara que os criteria não são só rótulos: cada opção vem com uma descrição curta do que ela cobre. É isso que ancora a decisão
O erro comum: rótulo vago tipo "outros" sem descrição nenhuma. Vira ralo, e todo ticket ambíguo cai ali
- Declare a urgência como
score
Aqui a régua é ordinal, uma lista do menos pro mais:
questions["urgency"] = {
"type": "score",
"instructions": "How urgent is this request?",
"criteria": ["not urgent", "soon", "critical deadline or blocking issue"]
}
E agora o ponto que quase todo mundo erra de primeira
O valor devolvido no score não é a classe vencedora, é o nível esperado: o índice do nível ponderado pelas probabilidades, acompanhado da distribuição e da confiança
Ou seja, é valor contínuo, não categoria. Um 1.6 significa "entre soon e crítico, puxando pro crítico", e essa nuance é exatamente o que tu quer numa fila de prioridade
O erro comum deste passo: arredondar o score pra classe logo de cara e jogar fora a distribuição. Aí você perde a informação mais útil que o modelo te deu
- Frustração como
scoree reembolso comonoul
Frustração segue a mesma lógica ordinal. A régua abaixo é um exemplo que você define pra sua operação, não um padrão oficial:
questions["frustration"] = {
"type": "score",
"instructions": "How frustrated does the sender sound?",
"criteria": ["neutral", "annoyed", "angry", "about to churn"]
}
questions["refund_requested"] = {
"type": "noul",
"instructions": "Does the sender ask for money back?"
}
O noul é a terceira primitiva: pergunta sim/não que devolve P(verdadeiro) calibrada. Não é um booleano seco, é uma probabilidade, e isso muda como tu escreve a regra depois
- Rode tudo de uma vez e leia as respostas
As três perguntas vão juntas, num único predict:
answers = agent.predict(state, questions)
print(answers["department"]["choice"])
print(answers["urgency"]["score"])
Cada opção é pontuada no próprio token marcador de máscara e depois passa por softmax dentro daquela pergunta, o que significa que o espaço de respostas é definido por requisição
Quer adicionar um departamento novo amanhã? Adiciona no dicionário. Sem retreino, sem fine-tune, sem nada 😀
O erro comum: fazer uma chamada por pergunta. Manda tudo no mesmo dicionário, que o modelo avalia o conjunto em lote
- Use o pacote pronto de triagem
Se tu não quer escrever pergunta nenhuma pra começar, o laya já traz pacotes prontos. O de triagem cobre intenção, urgência, frustração e churn:
agent.predict({"message": "My payment failed twice"}, laya.triage_questions())
Existem vizinhos pro resto da fila: router_questions(), guard_questions() e moderation_questions()
- Em produção, troque pelo Router embutido
O Router é o caminho recomendado: ele detecta script e idioma antes do forward pass e despacha pro checkpoint adequado
from laya import Router
router = Router(preload=True)
router.preload(["english", "multilingual"])
answers = router.predict(state, questions)
Com GPU, dá pra subir com Router(preload=True, device="cuda")
O erro comum aqui é de expectativa, não de código: esperar acerto perfeito em zero-shot, sem medir nada na sua própria fila
Como usar as respostas na sua fila de suporte
O modelo te dá números. Quem transforma número em ação é você
As regras operacionais mais diretas:
- Roteamento:
answers["department"]["choice"]define a fila de destino. Como o espaço de opções é fixo, não existe chance de aparecer um time que não existe no seu sistema - Escalonamento: urgência acima de um limiar sobe o ticket na fila ou aciona plantão
- Priorização por frustração: score alto de frustração com churn provável merece atendimento humano antes de qualquer macro automática
- Flag de reembolso: a probabilidade do
noulpuxa faturamento pra conversa desde o primeiro toque
Agora o detalhe que separa quem só copiou o código de quem entendeu a ferramenta
Calibre o limiar com a distribuição, não com o argmax
Um ticket com 0.51 na opção vencedora e outro com 0.94 não são a mesma decisão, mesmo que o argmax seja idêntico. Se a sua regra olha só o rótulo vencedor, você jogou a calibração no lixo e transformou um modelo probabilístico num classificador burro
O caminho é rodar numa amostra da fila, olhar a distribuição real dos scores no SEU domínio e escolher onde cortar entre "roteia automático" e "manda pra um humano conferir"
Não existe número mágico aqui, o corte depende do seu volume e do custo de errar
E vale lembrar que triagem é só uma etapa: se você já tem automação de tickets com n8n rodando, o laya entra como o nó de decisão dentro do fluxo que você já mantém, em vez de virar uma stack paralela
Perguntas tipadas x prompt aberto de LLM na triagem
| Critério | Perguntas tipadas (laya) | Prompt aberto de LLM |
|---|---|---|
| Formato de saída | Enum fixo com probabilidade por opção | Texto pra parsear (JSON na esperança) |
| Categoria inventada | Impossível por construção | Possível |
| Latência | 33 ms por pergunta e 7,2 ms por pergunta em lote na T4 | Variável |
| Custo | Pesos Apache 2.0, execução local, sem assinatura de API | Depende do provedor |
| Calibração | Probabilidades calibradas, ECE de 0,081 após ajuste de temperatura por domínio | Sem garantia de calibração |
| Espaço de respostas | Muda por requisição via option markers com token de máscara + softmax por pergunta, sem retreino | Muda editando o prompt |
| Geração de texto | Nenhuma | É o modo de operação |
O resumo honesto da tabela: o laya não substitui LLM pra escrever a resposta ao cliente
Ele substitui a LLM na parte em que você só queria uma decisão, e estava pagando token de geração (e risco de parsing) pra conseguir isso
Vale usar o laya na triagem hoje? A ressalva dos números
Aqui é onde eu preciso ser chato, porque o número bonito vem com asterisco
No benchmark typed-decisions, o checkpoint ajustado do laya marca 0,766 de acurácia argmax contra 0,727 do Jev, com ECE de 0,081 após ajuste de temperatura por domínio
Parece ótimo. Só que esse checkpoint foi ajustado no split de treino do próprio benchmark
Os checkpoints base, em zero-shot, ficam perto do acaso: 0,362 e 0,352, contra baseline aleatória de 0,318 e baseline de classe majoritária de 0,461
Leu direito? A classe majoritária bate os dois em zero-shot 😅
Avaliação independente chega na mesma conclusão: o laya é uma base excelente pra especializar, e não um oráculo zero-shot pra plugar e esquecer
Isso não mata a ferramenta, muda o jeito de adotar ela
A recomendação prática fica assim:
- Comece pelos pacotes prontos, tipo
triage_questions(), só pra ter um baseline rodando - Meça na SUA fila, com tickets reais já rotulados por humano
- Compare o acerto por pergunta, não no agregado (departamento costuma ser bem mais fácil que frustração)
- Planeje fine-tune com seus tickets rotulados se os números não fecharem
Se você já avaliou o Jev na triagem de tickets, vale rodar os dois na mesma amostra: é a única comparação que importa de verdade, a que usa os seus dados
Conclusão
Modelar triagem como pergunta tipada muda o problema de lugar
Você para de rezar pro JSON vir bem formado e passa a desenhar o espaço de decisão: choice pro departamento, score ordinal pra urgência e frustração, noul pra sim/não com probabilidade calibrada
Tudo em um forward pass, local, com pesos Apache 2.0 e sem categoria inventada aparecendo às 3 da manhã
O próximo passo é simples e não custa nada: abre a demo no Hugging Face Spaces, cola cinco tickets reais da sua fila na aba de triagem e olha a saída
Depois roda triage_questions() numa amostra maior e compara com a classificação que o seu time humano já fez
Só com esse número na mão é que faz sentido falar em fine-tune…
Até o próximo post! 😀
Perguntas frequentes
Dá pra fazer triagem de tickets com laya em português?
Dá sim, usando o checkpoint laya-multilingual, que tem 322M de parâmetros sobre mmBERT-base, contexto de 1024 tokens e mais de 100 idiomas. Pra fila de suporte em português, esse é o checkpoint natural, até porque o contexto maior ajuda com aquele textão de reclamação que o cliente manda.
O laya já vem pronto pra triagem de suporte ou eu preciso montar tudo do zero?
O laya traz pacotes de perguntas prontos, e um deles é o triage_questions(), voltado justamente pra triagem de suporte: intenção, urgência, frustração e churn. Dá pra chamar direto com agent.predict(state, laya.triage_questions()) em vez de declarar cada pergunta na mão.
Como o laya evita inventar um departamento que não existe na triagem de tickets?
Porque ele nunca gera texto: cada opção da pergunta choice é pontuada no próprio token marcador de máscara e passa por softmax dentro daquele conjunto fixo de criteria. Resposta malformada ou categoria fora do enum são impossíveis por construção, então não tem como sair um ‘suporte premium’ que não existe no seu sistema.
Qual a diferença entre score e choice na hora de montar a triagem?
O choice escolhe uma opção entre várias e devolve probabilidade por opção, como no exemplo de roteamento por departamento (billing, technical, sales). Já o score trabalha com uma régua ordinal e devolve o valor esperado, ou seja, a média ponderada pelas probabilidades mais a distribuição e a confiança, o que é ótimo pra urgência e frustração.
Preciso treinar o laya antes de usar em produção pra triagem de tickets?
Os checkpoints base ficam perto do acaso em zero-shot no benchmark typed-decisions, com 0,362 e 0,352 de acurácia contra 0,318 de baseline aleatória e 0,461 de baseline por classe majoritária. Já o checkpoint ajustado chega a 0,766 de acurácia, o que reforça a avaliação de que o laya é uma base excelente pra especializar, não um oráculo zero-shot pra plugar e esquecer.
A triagem com laya é rápida o suficiente pra rodar em cada ticket que chega?
Sim, os números oficiais falam em cerca de 33 ms pra uma pergunta e 7,2 ms por pergunta quando roda em lote, numa GPU T4, então dá pra rodar departamento, urgência, frustração e flag de reembolso juntos sem virar gargalo na fila.
Formações
Formação Vibe Coding
Do Prompt ao Produto: Crie Software Real com IA
- 474 aulas
- 20 projetos
- 39h 27min
Blog | Mais populares
O que significa “ChatGPT network error” e como resolver
O “ChatGPT Network Error” é uma ocorrência frequente na rotina de muitos usuários do ChatGPT. Porém, poucos compreendem seu significado, quando esse erro surge, etc. […]

Checklist de segurança n8n VPS pública: guia essencial para proteger sua instalação
Checklist de segurança n8n VPS pública: guia essencial para proteger sua instalação A popularidade da automação de processos com o n8n está em alta, principalmente […]

Como usar o Antigravity do Google: guia completo do zero ao primeiro app
Aprenda neste guia prático como usar o Antigravity do Google: descubra a instalação, configuração, criação de projetos com o Agent Manager e o primeiro deploy, […]
