Como usar o Jev para triar a mensagem do usuário antes de acionar o agente

Fluxo de triagem com Jev decidindo entre atender, pedir dado ou escalar para humano
Resposta rápida

A triagem com Jev é uma camada que roda antes do agente e decide o destino de cada mensagem: atender, pedir um dado que falta ou mandar direto para um humano. O Jev, modelo de decisão da TypeSafe AI, não gera texto, ele devolve respostas tipadas (Choice, Score ou Noul) com confiança calibrada. Você monta uma Choice para o destino e perguntas Noul em paralelo no mesmo state, e trata o caso ambíguo como caminho próprio: de 0.30 a 0.70 é incerto, acima de 0.70 é sim. Custa US$ 0,042 por milhão de tokens de entrada, e a saída não é cobrada

Fala aí, beleza? Nem toda mensagem que chega deveria acordar o seu agente 😛

Pensa no fluxo normal: o usuário manda qualquer coisa e o LLM já entra em campo, lê tudo, raciocina, gasta token e tempo

Só que muitas vezes o pedido é algo que o agente não consegue atender, ou depende de um dado que ele não tem (número do pedido, conta do usuário), ou é alguém pedindo pra falar com uma pessoa

Aí o modelo fica tentando responder o que não devia, e a conversa fica zoada

A ideia deste post é colocar uma camada de triagem na entrada, antes do agente, usando o Jev

O Jev é um modelo de decisão da TypeSafe AI, lançado em 15 de setembro de 2026 como o primeiro modelo público da linha que a empresa chama de System One Models

E o detalhe que muda tudo: ele não gera texto

Ele lê um estado (texto ou JSON) e devolve respostas tipadas com confiança calibrada

Ou seja: o LLM gera, o Jev decide 🙂

Bora ver na prática?

Por que triar antes de acionar o agente?

Se você já montou um agente, sabe que o LLM é ótimo pra raciocinar, planejar e escrever

Porém usar ele pra decidir "essa mensagem vai pra onde?" é tipo chamar o dev sênior pra separar a correspondência do escritório haha

A divisão de papéis fica assim: o LLM raciocina, planeja e gera, enquanto o Jev cuida de classificação, roteamento, nota, triagem e decisões com respostas delimitadas

E o que seria "resposta delimitada"?

É uma resposta que cabe num formato fechado, sem texto livre, e o Jev tem três tipos disso:

Tipo O que devolve Pra que serve na triagem
Choice Uma opção dentre opções nomeadas, a probabilidade de cada opção e a confiança Decidir o destino da mensagem (atender, pedir dado, humano)
Score Uma nota numa rubrica ordenada (pode ser fracionária), a probabilidade de cada nível, uma legenda e a confiança Medir grau, tipo urgência
Noul A probabilidade de uma hipótese de sim/não Perguntas binárias, tipo "o usuário pediu uma pessoa?"

A própria documentação traz um exemplo de triagem que serve de molde: um ticket de loja de calçados ("My running shoes arrived in the wrong size…") com uma Choice que decide a equipe entre returns, shipping e billing

A nossa triagem segue exatamente esse padrão, só que as opções são o destino da mensagem e não a equipe

O que você precisa antes de começar?

Se liga na lista, é curtinha:

  • Conta na TypeSafe AI: o cadastro está aberto pra qualquer pessoa, e conta nova ganha US$ 5 de crédito
  • Chave de API: gerada em console.typesafe.ai/settings/keys e exportada na variável TYPESAFE_API_KEY
  • Python 3.10 ou superior com o typesafe-sdk, ou Node.js 20 ou superior com o @typesafe-ai/sdk

Os dois SDKs usam o modelo jev-latest por padrão, então tu nem precisa informar o modelo no começo

E tem o argumento que faz a triagem valer em TODA mensagem: o Jev custa US$ 0,042 por milhão de tokens de entrada, e os tokens de saída não são cobrados

Como ele não escreve resposta, você paga basicamente pela leitura da mensagem 😀

Passo a passo: montando a camada de triagem com o Jev

Agora sim, mão na massa

Passo 1: instalar o SDK e autenticar

No Python, tu roda:

pip install typesafe-sdk
# ou
uv add typesafe-sdk

Se o seu projeto é JavaScript:

npm install @typesafe-ai/sdk

Depois exporta a chave:

export TYPESAFE_API_KEY="sk-..."

Erro comum deste passo: esquecer a variável de ambiente, ou exportar num terminal e rodar o script em outro

Os SDKs leem a chave de TYPESAFE_API_KEY, então se ela não estiver ali, não tem autenticação

Já perdi um tempinho bom com esse tipo de coisa, confere antes de sair debugando o código hehe

Passo 2: modelar a Choice de destino

Aqui mora o coração da triagem

Na Choice, o campo criteria é um mapa: cada chave é o nome de uma opção e cada valor é a descrição dela

Pra nossa entrada, três opções resolvem:

  • atendivel: o pedido é algo que o agente consegue resolver com o que ele já tem
  • falta_dado: o pedido é atendível, mas depende de uma informação que não veio na mensagem
  • humano: o caso precisa de uma pessoa

O segredo é escrever descrições mutuamente exclusivas

Cada mensagem deveria caber em uma opção só, sem ficar em cima do muro entre duas

Erro comum deste passo: opções sobrepostas

Se falta_dado e humano descrevem quase a mesma coisa, a probabilidade se divide entre as duas e a confiança despenca, mesmo numa mensagem clarinha

Antes de culpar o modelo, relê as descrições 😛

Passo 3: adicionar perguntas Noul em paralelo

A Choice diz pra onde vai, mas às vezes você quer um sinal binário separado

Tipo:

  • A mensagem pede algo que o agente consegue fazer?
  • O usuário pediu explicitamente para falar com uma pessoa?

Isso é Noul: a probabilidade de uma hipótese de sim/não

E aqui vem a parte massa: a requisição tem três campos no nível de cima, state (o conteúdo avaliado), model e questions, que é um mapa de ids de pergunta para objetos de pergunta

Ou seja, várias perguntas são avaliadas em paralelo sobre o mesmo state

Você coloca a Choice de destino e as Noul lado a lado, cada uma com seu id (destino, pode_atender, pediu_humano e por aí vai)

Erro comum deste passo: fazer uma chamada pra cada pergunta

Não precisa! Todas cabem na mesma requisição, em cima do mesmo state

Passo 4: chamar o Jev e ler a resposta inteira

Com o SDK Python, o uso básico é importar o TypeSafeClient e chamar client.system_one(state, questions) dentro de um with:

from typesafe_sdk import TypeSafeClient

state = "Quero cancelar meu pedido, mas não lembro o número dele"

questions = {
    "destino": {
        "criteria": {
            "atendivel": "O agente resolve o pedido só com o que veio na mensagem",
            "falta_dado": "O pedido é atendível, mas falta uma informação (ex: número do pedido)",
            "humano": "O caso precisa ser tratado por uma pessoa",
        },
    },
}

with TypeSafeClient() as client:
    result = client.system_one(state, questions)
    print(result)

Na resposta da Choice você recebe a opção vencedora, a probabilidade de cada opção e a confiança, que vai de 0 a 1 e é derivada da distribuição de probabilidade da resposta

Erro comum deste passo: olhar só a opção vencedora

Uma vitória de atendivel com confiança alta e uma vitória apertada com confiança baixa são situações BEM diferentes

E é justamente isso que a próxima seção resolve

Como tratar o caso ambíguo sem travar a conversa?

Aqui é onde a maioria das triagens quebra

O jeito ingênuo é usar um limiar fixo de 0.5 no Noul: passou de 0.5 é sim, abaixo é não

Só que aí 0.49 e 0.51 disparam ações opostas, sendo que os dois valores são, na real, incertos

A própria documentação do Noul sugere outra abordagem: tratar de 0.30 a 0.70 (limites incluídos) como incerto e acima de 0.70 como sim

O que fica abaixo de 0.30 você trata como não

def classifica_noul(probabilidade: float) -> str:
    if probabilidade > 0.70:
        return "sim"
    if probabilidade >= 0.30:
        return "incerto"
    return "nao"

Na Choice, a orientação é parecida, com três caminhos baseados na confiança:

  • Confiança alta: automatiza (aciona o agente, ou pede o dado faltante se a opção for falta_dado)
  • Faixa do meio: vai pra revisão
  • Confiança baixa: vai pra um humano

E quais números usar?

A documentação não crava um valor universal, e faz sentido: os limiares devem acompanhar o custo de uma ação errada

Se errar o destino só gera uma pergunta a mais, tu pode ser mais permissivo

Se errar significa o agente mexer em pedido de cliente sem o dado certo, aperta o limiar

Na prática, deixa os dois cortes da Choice como configuração, e não cravados no código:

def rota_choice(opcao: str, confianca: float, limiar_alto: float, limiar_baixo: float) -> str:
    if confianca >= limiar_alto:
        return opcao  # automatiza: atendivel, falta_dado ou humano
    if confianca >= limiar_baixo:
        return "revisao"
    return "humano"

E como achar esses valores?

Roda a triagem em mensagens reais do seu histórico e olha em que faixa de confiança o Jev começa a errar o destino: o corte alto fica acima dessa faixa, e quanto mais caro for o erro, mais alto ele sobe

O que ficar entre os dois cortes vai pra revisão, e o que ficar abaixo do corte baixo vai direto pra uma pessoa

Já nos Noul tu tem o ponto de partida da própria documentação: a faixa incerta de 0.30 a 0.70, que a função classifica_noul ali de cima já aplica

Agora, uma decisão de design que é do SEU sistema (não do Jev): o incerto não precisa travar o usuário

Enquanto a revisão acontece, o agente pode mandar uma resposta de espera ou uma pergunta de esclarecimento, tipo "você consegue me passar o número do pedido?"

Assim o caso ambíguo vira um caminho próprio, e não um buraco na conversa

Erro comum desta etapa: tratar incerto como não

Isso joga fora justamente as mensagens que mais precisavam de atenção

Onde essa triagem faz diferença?

Tem alguns use cases em que essa camada se paga rapidinho

Suporte com roteamento por equipe: é o molde do exemplo oficial, com returns, shipping e billing

Você pode até encadear: primeiro decide se é atendivel, falta_dado ou humano, e depois roteia por equipe

Chatbot que depende de dado: quando o pedido precisa de número do pedido ou da conta, a triagem pega isso antes de chamar o LLM

O agente já entra sabendo que precisa pedir a informação, em vez de alucinar uma resposta

Pedido explícito de humano: se o Noul de pediu_humano vem alto, a mensagem pula o agente direto

Nada mais irritante que pedir uma pessoa e receber três parágrafos gerados por IA haha

Decisão de grau, não de categoria: quando a pergunta é "quão urgente é isso?", o tipo certo é o Score

Você monta uma rubrica ordenada de urgência e recebe uma nota ponderada, a probabilidade de cada nível e a confiança

E a mesma lógica de camada na entrada vale pra outras checagens, como moderar conteúdo enviado por usuários ou detectar jailbreak antes do LLM

Tudo roda no mesmo state, como perguntas em paralelo

Próximo passo

Recapitulando o que vimos:

  • O Jev decide, o agente gera
  • A Choice define o destino (atendivel, falta_dado, humano) com descrições que não se sobrepõem
  • As perguntas Noul rodam em paralelo no mesmo state, na mesma requisição
  • A confiança importa tanto quanto a opção vencedora
  • O caso ambíguo vira caminho próprio, com revisão e uma resposta que não trava o usuário

O próximo passo é simples: cria a conta, usa os US$ 5 de crédito inicial e roda a Choice e os Noul em mensagens reais do seu histórico

Olha onde o Jev acerta, onde ele fica na faixa incerta, e calibra os limiares pelo custo de errar no seu caso

Se tu montar essa triagem com Jev aí no seu projeto, me conta como ficou, bora trocar uma ideia 😀

Até o próximo post!

Perguntas frequentes

Quanto custa usar o Jev para fazer a triagem de cada mensagem?

O Jev cobra US$ 0,042 por milhão de tokens de entrada, e os tokens de saída não são cobrados. Como ele não gera texto, o custo da triagem fica basicamente restrito à leitura do state enviado na requisição.

Preciso entrar numa lista de espera para criar conta na TypeSafe AI?

Não, o cadastro está aberto para qualquer pessoa. Toda conta nova ganha US$ 5 de crédito, o suficiente pra testar a camada de triagem antes de decidir se vale colocar em produção.

O Jev consegue decidir quando uma mensagem precisa ir para um humano?

Sim, esse é justamente o tipo de resposta que a Choice resolve na triagem: você cria uma opção como humano dentro do campo criteria e descreve quando ela se aplica. A confiança devolvida ajuda a decidir se encaminha direto ou se pede confirmação antes.

Qual a diferença entre usar Choice, Score e Noul na triagem com Jev?

Choice escolhe uma opção entre opções nomeadas e devolve a probabilidade de cada uma com a confiança, ótimo pra decidir o destino da mensagem. Score dá uma nota numa rubrica ordenada, útil pra medir grau como urgência. Noul responde só a probabilidade de uma hipótese de sim/não, ideal pra perguntas binárias como se o usuário pediu um humano.

O Jev substitui o LLM que está dentro do agente?

Não, a ideia é dividir papéis: o LLM continua raciocinando, planejando e gerando a resposta final. O Jev entra antes disso, cuidando de classificação, roteamento e triagem com respostas tipadas e confiança calibrada.

Dá para montar essa triagem com Jev em projetos Node.js?

Dá sim, a TypeSafe AI mantém o SDK @typesafe-ai/sdk para JavaScript, que exige Node.js 20 ou superior. Ele lê a chave da mesma variável TYPESAFE_API_KEY e usa o jev-latest como modelo padrão, igual ao SDK Python.



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 Claude Code

Formação Claude Code

Domine Claude Code do absoluto zero até o avançado

  • 120 aulas
  • 4 projetos
  • 9h 48min

Blog | Mais populares