Como quebrar uma regra de negócio complexa em perguntas sim/não no Laya

Fluxo de decisão mostrando como estruturar perguntas sim/não no Laya para regras de negócio complexas
Resposta rápida

Pra decidir uma regra de negócio complexa com perguntas sim/não no Laya, quebre a política em condições atômicas e transforme cada uma numa pergunta noul, que devolve P(true) de 0.0 a 1.0. Cada pergunta testa uma única propriedade e recebe seu próprio limiar, aproveitando a calibração do modelo. A ordem da decisão fica no seu código: primeiro os critérios eliminatórios, por último os de desempate. Todas as perguntas vão juntas num único forward pass, então a ordem serve pra lógica e pra explicar a decisão, não pra economizar chamada.

Fala aí, beleza? Se você já jogou um regulamento inteiro numa pergunta só pra IA decidir, sabe o que sai: uma resposta confusa, que ninguém consegue auditar

Uma pergunta gigante sobre a política inteira dá resposta confusa

Várias perguntas pequenas dão respostas confiáveis 🙂

É isso que a gente vai montar aqui: pegar uma regra cheia de condições (um regulamento, um critério de aprovação, uma regra de elegibilidade) e quebrar em perguntas sim/não no Laya

Que Laya?

É uma família de modelos de decisão de pesos abertos, sob licença Apache 2.0, feita pela Convai Innovations

O código oficial fica no repositório NandhaKishorM/laya no GitHub e os pesos ficam na conta da Convai no Hugging Face, em convaiinnovations/laya

Ele não é autorregressivo: lê um estado e perguntas tipadas e devolve respostas estruturadas com probabilidades, sem gerar texto livre

Ou seja, não tem prosa pra parsear nem resposta malformada pra tratar, e pra regra de negócio isso é MUITO massa

O que você precisa antes de começar:

A lista é curta:

  • Python 3.10 ou superior
  • O pacote instalado com pip install laya
  • A política escrita por extenso, do jeito que o time de negócio usa hoje
  • Um estado pra ser avaliado: pode ser texto, e-mail, ticket ou um documento JSON

Os pesos ficam no Hugging Face e tu carrega o checkpoint direto pelo Python:

import laya

# inglês (~808 MB)
modelo_en = laya.load("convaiinnovations/laya")

# multilíngue, mais de 100 idiomas, incluindo português (~647 MB)
modelo_multi = laya.load("convaiinnovations/laya", subfolder="multilingual")

# checkpoint de decisões tipadas
modelo_tipado = laya.load("convaiinnovations/laya", subfolder="typed-decisions")

Se o seu conteúdo está em português, o caminho é o multilíngue

No projeto também existe um roteador que escolhe o checkpoint pelo idioma detectado, o que ajuda quando chega texto em várias línguas

Sobre hardware: a referência publicada de latência é numa GPU T4, e os números estão no passo 5

Passo a passo: da política longa às perguntas sim/não

Antes do como, o porquê

O Laya tem três primitivas de pergunta: choice, score e noul

A noul é a pergunta sim/não, e devolve P(true), a probabilidade de a afirmação ser verdadeira, de 0.0 a 1.0

A própria documentação recomenda perguntas explícitas, estreitas e atômicas, e dividir uma pergunta composta em perguntas separadas que testem uma propriedade cada

Se liga no motivo: separando, cada pergunta ganha calibração e limiar independentes

Pra ficar concreto, vou usar esta política de exemplo:

O cliente tem direito a reembolso quando pede reembolso de forma explícita E (houve cobrança duplicada OU a compra está dentro do prazo da política e o produto não foi usado)

Bora ver na prática?

  1. Liste as condições, uma por linha

Pegue a política e separe cada "e" e cada "ou" numa linha própria

No exemplo, fica assim:

  • o cliente pediu reembolso de forma explícita
  • houve cobrança duplicada
  • a compra está dentro do prazo da política
  • o produto não foi usado

E anote à parte como elas se ligam: pedido E (duplicada OU (prazo E sem uso))

Essa ligação não vai pro modelo, ela vira if no teu código

Se a tua dor hoje é outra, tipo explicar essa mesma lógica num prompt pra gerar código, vale ver como descrever regra de negócio cheia de exceções no Claude Code

O erro comum deste passo: manter duas condições na mesma frase ("pediu reembolso e o produto não foi usado"), o que já nasce como pergunta composta

  1. Reescreva cada condição como afirmação atômica e verificável no estado

Cada linha vira uma afirmação que dá pra checar só olhando o ticket, o e-mail ou o JSON

Compara:

  • Ruim: "Esse cliente tem direito a reembolso pela nossa política?"
  • Bom: "O usuário pede reembolso de forma explícita?"
  • Bom: "O usuário relata ter sido cobrado duas vezes pela mesma compra?"
  • Bom: "O usuário diz que já usou o produto?"

A primeira obriga o modelo a interpretar a política inteira

As outras testam UMA coisa cada

Tem um caso relatado bem ilustrativo disso: a pergunta combinada deu 0,39 e a versão atômica deu 0,93

E repara numa coisa: "dentro do prazo" muitas vezes nem precisa ir pro modelo

Se o JSON tem a data da compra, o teu código resolve com uma conta simples, sem probabilidade nenhuma no meio

O erro comum deste passo: escrever pergunta vaga, que depende de conhecer a regra toda pra ser respondida

  1. Monte as perguntas no formato noul e chame o predict

Aqui eu sigo a estrutura do exemplo oficial do quickstart: cada pergunta com id, type e instructions, e a chamada router.predict(state, questions)

Que router?

É o roteador do projeto, aquele que escolhe o checkpoint pelo idioma detectado, e a criação dele tá no quickstart oficial no PyPI

state = """Oi, fui cobrado duas vezes no cartão pela mesma assinatura.
Quero o dinheiro da segunda cobrança de volta."""

questions = [
    {
        "id": "refund_requested",
        "type": "noul",
        "instructions": "Does the user explicitly request a refund?",
    },
    {
        "id": "duplicate_charge",
        "type": "noul",
        "instructions": "Does the user report being charged twice for the same purchase?",
    },
    {
        "id": "product_used",
        "type": "noul",
        "instructions": "Does the user say they already used the product?",
    },
]

# router: o roteador do projeto, criado como no quickstart oficial (link acima)
resultado = router.predict(state, questions)

A primeira pergunta é literalmente a do exemplo oficial, as outras seguem o mesmo molde

O erro comum deste passo: usar choice ou score pra uma condição que é binária, sim ou não

  1. Defina um limiar por pergunta

O modelo é treinado pra que as probabilidades batam com a frequência observada: das respostas dadas a 80%, cerca de 80% devem estar certas

É essa calibração que permite um corte diferente pra cada pergunta

Pensa no custo do erro de cada uma

Aprovar reembolso por engano numa "cobrança duplicada" pode doer mais que deixar passar um "produto usado", então o corte da duplicada pode ser mais exigente

Não existe valor oficial recomendado de limiar pra noul, então quem define é você, olhando os seus casos reais (passo 6)

O erro comum deste passo: usar o mesmo corte pra tudo, tipo 0,5 em todas as perguntas, e jogar fora a vantagem de ter separado

  1. Ordene a lógica de decisão no seu código

A ordem é você quem define, e a regra de ouro é: primeiro os critérios eliminatórios e mais frequentes, que descartam cedo o que não se aplica, e por último os de desempate

def decidir(p, limiar, dentro_do_prazo):
    # p: P(true) de cada pergunta, extraído do resultado do predict
    # limiar: o corte que você calibrou pra cada pergunta
    # dentro_do_prazo: calculado no seu código a partir da data

    # 1. eliminatória e mais frequente: nem é pedido de reembolso
    if p["refund_requested"] < limiar["refund_requested"]:
        return "nao_se_aplica", "não há pedido explícito de reembolso"

    # 2. o OU da regra: cobrança duplicada aprova direto
    if p["duplicate_charge"] >= limiar["duplicate_charge"]:
        return "aprovar", "cobrança duplicada"

    # 3. condição que é conta, resolvida sem o modelo
    if not dentro_do_prazo:
        return "negar", "fora do prazo da política"

    # 4. desempate
    if p["product_used"] >= limiar["product_used"]:
        return "negar", "produto já utilizado"

    return "aprovar", "dentro do prazo e sem uso"

Repara que cada return já sai com o motivo, e isso vale ouro na hora de explicar a decisão pro time de suporte 😀

Agora o ponto que confunde muita gente: todas as perguntas sobre o mesmo estado são respondidas num único forward pass

Na GPU T4 a latência medida foi de 33 ms pra uma pergunta e 7,2 ms por pergunta em lote

Então a ordem dos if serve pra decidir e pra explicar o motivo de cada decisão, não pra economizar chamada ao modelo

O erro comum deste passo: tentar economizar chamando o modelo pergunta por pergunta, só avançando se a anterior passar

Você paga mais latência e não ganha nada, manda tudo junto e deixa o if fazer o trabalho

  1. Valide com casos reais e ataque as perguntas que confundem

Separa uma leva de tickets (ou e-mails, ou JSONs) que alguém do time já decidiu na mão, roda e compara

Olha principalmente onde o modelo erra entre categorias parecidas

Tem um caso relatado da comunidade que mostra bem isso: um juiz baseado em regra, decomposto em 3 perguntas sim/não, chegou a 95% de acurácia geral

Mas ainda separava mal "lista incompleta" de "erro real"…

Número geral bonito escondendo uma confusão específica, clássico haha

A saída nesse cenário é criar uma pergunta atômica só pra essa distinção

No nosso exemplo de reembolso, se "cobrado duas vezes pela mesma compra" se misturar com "comprou dois produtos diferentes", você adiciona uma pergunta que testa só isso

O erro comum deste passo: olhar só a acurácia geral e declarar vitória

Onde essa decomposição funciona melhor?

Qualquer regra que hoje vive num PDF de política e é aplicada por gente lendo caso a caso é candidata

Três exemplos pra tu visualizar (ilustrativos, pra mostrar o formato):

Caso Perguntas atômicas Eliminatória
Elegibilidade a reembolso em tickets de suporte O usuário pede reembolso de forma explícita? / O usuário relata cobrança duplicada? / O usuário diz que já usou o produto? Pedido explícito de reembolso
Aprovação de cadastro a partir de um JSON A descrição do negócio menciona produto proibido pelo regulamento? / O nome fantasia é coerente com a atividade descrita? / A descrição está preenchida com conteúdo real, e não texto genérico? Produto proibido pelo regulamento
Triagem de e-mails por regulamento interno O remetente ameaça ação judicial? / O e-mail pede cancelamento de contrato? / O e-mail contém dado pessoal de terceiro? Ameaça de ação judicial (vai direto pro jurídico)

No cadastro, o estado é o próprio JSON, e o que for campo objetivo (preenchido ou não, formato) continua sendo validado no código

O modelo entra onde precisa ler texto e interpretar

Na triagem, repara que "assunto jurídico ou reclamação formal" seria uma pergunta composta, por isso virou perguntas separadas

E a zona cinzenta?

Todo limiar deixa uma faixa em que a probabilidade não é alta nem baixa o suficiente pra agir com segurança

O checkpoint inglês tem uma saída act/escalate (agir ou escalar), que é o caminho natural pra mandar esses casos pra um humano em vez de decidir no chute

Próximo passo:

Recapitulando a ideia toda:

  • uma propriedade por pergunta
  • um limiar por pergunta, aproveitando a calibração
  • eliminatórias primeiro, desempate por último, com a ordem no seu código
  • tudo num único forward pass, sem chamar o modelo pergunta por pergunta

O próximo passo prático é pegar uma regra real do seu produto, dessas que só uma pessoa do time sabe aplicar direito, e quebrar em perguntas noul

Se o conteúdo está em português, testa com o checkpoint multilíngue (subfolder="multilingual") e compara com as decisões que já foram tomadas na mão

O código fica no repositório NandhaKishorM/laya no GitHub e os pesos em convaiinnovations/laya no Hugging Face, os dois com README que vale a leitura antes de sair codando

Faça o teste e me conta onde o modelo mais confundiu 🙂

Até o próximo post!

Perguntas frequentes

Qual a diferença entre noul, choice e score no Laya?

São as três primitivas de pergunta do Laya. A noul é a pergunta sim/não e devolve P(true), a probabilidade de a afirmação ser verdadeira, de 0.0 a 1.0. Choice e score existem pra outros formatos de resposta, mas pra regra de negócio binária o tipo certo é noul.

Por que uma pergunta composta dá resposta pior que uma pergunta atômica no Laya?

Porque o modelo precisa interpretar várias condições de uma vez só, e isso derruba a calibração. Num caso relatado, a pergunta combinada deu 0,39 e a mesma regra quebrada em pergunta atômica deu 0,93.

Dá pra fazer perguntas sim/não no Laya em português?

Sim, usando o checkpoint multilíngue, carregado com laya.load("convaiinnovations/laya", subfolder="multilingual"). Ele cobre mais de 100 idiomas, incluindo português, e tem cerca de 647 MB.

Quanto tempo o Laya leva pra responder uma pergunta sim/não?

Na referência publicada numa GPU T4, uma pergunta isolada leva 33 ms. Em lote, esse tempo cai pra 7,2 ms por pergunta, já que várias perguntas tipadas sobre o mesmo estado saem num único forward pass.

O Laya escreve uma justificativa junto com a resposta sim/não?

Não. O Laya não é autorregressivo e não gera texto livre, ele só devolve probabilidades sobre opções definidas. Por isso não existe resposta malformada nem prosa pra parsear na saída.

Preciso reescrever a política inteira pro Laya entender a regra de negócio?

Não, e essa é a recomendação oficial: quebre a política em perguntas explícitas, estreitas e atômicas, cada uma testando uma propriedade só. A ligação lógica entre as condições (o E e o OU da regra) fica no seu código, não vai pro modelo.



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 30min

Blog | Mais populares