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

Fluxo de triagem de tickets com laya classificando urgência, frustração e departamento
Resposta rápida

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
Formação Recomendada

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

  1. 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

  1. 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

  1. 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

  1. 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

  1. Frustração como score e reembolso como noul

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

  1. 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

  1. 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()

  1. 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 noul puxa 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.



Escrito por | Matheus Battisti

Matheus Battisti
Fundador da Hora de Codar

Programador apaixonado pelo mundo das tecnologias, sempre buscando em aprender e se aprofundar em linguagens, frameworks e o que mais for necessário para executar um bom trabalho. Agora tem uma nova missão que é de passar seu conhecimento adiante para formar novos programadores e especializar mais os que já são.

Subscribe
Notify of
guest

0 Comentários
Oldest
Newest Most Voted

Formações

Formação Vibe Coding

Formação Vibe Coding

Do Prompt ao Produto: Crie Software Real com IA

  • 474 aulas
  • 20 projetos
  • 39h 27min

Blog | Mais populares