Como usar o Jev para decidir a próxima pergunta de um formulário de onboarding?

Um formulário adaptativo com Jev funciona assim: você joga as respostas já coletadas no campo state, transforma as perguntas que sobraram nas opções de um Choice (com uma opção de escape) e pede junto um Noul que estima se já dá pra encerrar. O Jev não devolve prosa, devolve resposta tipada com probabilidades e confidence, então seu código lê o ID da próxima pergunta e renderiza o campo, sem parsear texto. A cada resposta do usuário você atualiza o state e faz a próxima chamada, até o Noul dizer que chega.
Cada campo a mais no seu onboarding é um usuário a menos
Fala aí, beleza? A TypeSafe AI soltou o Jev, o primeiro modelo System One dela, e ele resolve exatamente o tipo de problema que a gente sempre tentou empurrar com LLM e nunca ficou confiável: decidir uma coisa e devolver isso em formato que o software consome direto
O Jev não gera texto
Ele devolve resposta tipada (Noul, Choice, Score) com probabilidades calibradas, e é isso que muda o jogo pro nosso caso aqui: em vez de pedir pra uma IA "escrever qual a próxima pergunta" e depois rezar pro seu parser entender a resposta, você entrega o catálogo de perguntas que ainda existem no seu formulário e recebe de volta qual delas pedir agora
Sem prosa, sem regex, sem alucinar um campo que não existe no seu banco
Bora montar esse fluxo?
O que você precisa antes de começar
Do lado da TypeSafe:
- Conta no
console.typesafe.ai, que agora tem cadastro aberto a qualquer pessoa (o waitlist caiu junto com a disponibilidade geral, anunciada em 21 de setembro de 2026) e vem com US$ 5 de crédito gratuito - Chave de API gerada na página API Keys do console: ela começa com
sk-e é exibida uma única vez, então copia e guarda no gerenciador de senhas antes de fechar a aba - A variável de ambiente
TYPESAFE_API_KEYconfigurada, porque o cliente oficial lê a chave dali e chamajev-latestpor padrão - SDK instalado:
pip install typesafe-sdk(Python 3.10+) ou@typesafe-ai/sdk(Node 20+)
Do lado da sua aplicação:
- Um formulário que já existe, com campos identificáveis
- Um banco de perguntas com IDs estáveis, tipo
objetivo_principal,tamanho_do_time,stack_principal
Esse segundo item é o mais importante do post inteiro, e vou repetir mais pra frente: o Jev vai escolher entre IDs que VOCÊ definiu. Se os IDs mudam a cada deploy, seu fluxo adaptativo quebra sozinho
Sobre custo, pra você dimensionar antes de escrever código: o preço publicado do Jev é de US$ 0,042 por 1 milhão de tokens de entrada, e os tokens de saída custam US$ 0
Como a saída é tipada e curtinha, quem pesa na conta é o seu state, ou seja, o histórico do onboarding que você manda junto
Curso de Jev: Sistemas Mais Inteligentes, Rápidos e Robustos
Desenvolva sistemas mais inteligentes, rápidos e robustos com Jev
Antes do adaptativo: o formulário base em HTML
Pra orquestrar campos com IA você precisa ter os campos, né? 😀
Pra começar do zero com formulário, este vídeo do canal mostra os principais inputs do HTML em 30 minutos, do text e select até os tipos mais específicos que você vai usar como destino das perguntas que o Jev escolher
Os três tipos de resposta e o papel de cada um aqui:
O Jev tem três tipos de pergunta, definidos pelo campo type, e todos compartilham type e instructions, cada um com seu criteria
No nosso formulário adaptativo, cada um ocupa um lugar bem específico:
| Tipo | O que devolve | Papel no formulário adaptativo |
|---|---|---|
| Choice | Opção escolhida, probabilidade de cada opção e confidence entre 0 e 1 |
Decide QUAL pergunta pedir agora, entre as que restaram |
| Noul | Um único número: a probabilidade de a resposta ser sim (0 = não, 1 = sim) | Decide SE já dá pra encerrar o onboarding |
| Score | Posição em um espectro | Posiciona o usuário (nível de senioridade, maturidade, urgência) sem precisar perguntar direto |
Guarda esse mapa na cabeça, porque o passo a passo é basicamente Choice + Noul rodando juntos em loop
Passo a passo: formulário de onboarding adaptativo com o Jev
1. Modelar o state com o que você já sabe:
O campo state aceita texto simples ou dados estruturados: string, objeto JSON ou array com contexto, exemplos e informações relacionadas, incluindo o estado atual da aplicação
Pra onboarding, o state é literalmente a ficha do usuário até agora:
{
"perfil_inferido": "dev solo, veio do plano free",
"respostas_coletadas": {
"stack_principal": "Next.js",
"tamanho_do_time": "1"
},
"campos_vindos_de_integracao": ["email", "nome_empresa", "pais"],
"perguntas_ja_feitas": ["stack_principal", "tamanho_do_time"]
}
Repara que eu mando também o que JÁ foi perguntado
Parece redundante, mas é o que evita o modelo insistir num campo que o usuário acabou de responder
O erro comum deste passo: jogar o formulário todo cru dentro do state, incluindo aquele textarea de 4 mil caracteres que o usuário colou. Mande dado normalizado, não o dump do banco
2. Transformar as perguntas restantes em opções de um Choice:
Aqui é o coração da ideia
Em vez de perguntar "qual a próxima pergunta?" em aberto, você fecha o universo: as opções do Choice são os IDs das perguntas que ainda faltam
Uma pergunta Choice suporta até 255 opções, o que é folgado demais pra qualquer onboarding sadio
E a documentação do Choice orienta descrever, em cada opção, o que pertence a ela, o que pertence à opção vizinha e exemplos representativos, usando os mesmos nomes de campo em todas as opções
Ou seja: criteria não é um rótulo, é a definição de fronteira entre as opções
{
"proxima_pergunta": {
"type": "Choice",
"instructions": "Escolha qual pergunta do onboarding faz mais sentido pedir AGORA, considerando o que já foi respondido no state",
"criteria": {
"objetivo_principal": {
"pertence": "o state não deixa claro o que o usuário quer resolver com o produto",
"nao_pertence": "já existe objetivo declarado em respostas_coletadas",
"exemplos": ["usuário só informou stack", "usuário veio do free sem contexto de uso"]
},
"volume_mensal": {
"pertence": "o objetivo já é claro e falta dimensionar escala para sugerir plano",
"nao_pertence": "o objetivo ainda não foi declarado",
"exemplos": ["objetivo é migrar API interna", "objetivo é automatizar suporte"]
},
"none_of_the_above": {
"pertence": "nenhuma pergunta restante agrega informação útil neste momento",
"nao_pertence": "existe pelo menos uma pergunta claramente relevante",
"exemplos": ["state já cobre perfil, objetivo e escala"]
}
}
}
}
Curso RecomendadoDesenvolva sistemas mais inteligentes, rápidos e robustos com JevConhecer cursoO erro comum deste passo: escrever criteria só com o enunciado da pergunta ("pergunta sobre volume"). Sem o "não pertence", duas opções vizinhas ficam intercambiáveis e a distribuição de probabilidade achata
Ah, e se a sua descrição de opção ficar comprida, dá pra quebrar: instructions, opções de Choice, níveis de Score e criteria de Noul aceitam estrutura JSON, com os dados em campos nomeados referenciados por nome
3. Sempre incluir a opção de escape:
Viu o none_of_the_above ali em cima? Ele não é enfeite
A própria documentação recomenda adicionar uma opção other ou none of the above quando a lista pode não cobrir todo input, justamente pro modelo poder dizer que nenhuma das outras serve
No formulário adaptativo, essa opção tem um significado lindo: "não tenho uma boa próxima pergunta"
E isso, no seu código, vira o gatilho de encerrar ou de cair na ordem fixa
O erro comum deste passo: deixar o Choice sem escape e forçar o modelo a escolher a menos ruim. Você acaba perguntando faturamento pra um dev solo que já disse que é hobby
4. Fazer a chamada e ler a resposta tipada:
A API do Jev tem um único endpoint que avalia um state contra um mapa de perguntas tipadas e devolve uma resposta por pergunta
Cru, é isso:
curl -X POST https://api.typesafe.ai/v1/systemone \
-H "Authorization: Bearer $TYPESAFE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "jev-latest",
"state": { "...": "seu state aqui" },
"questions": { "...": "seu mapa de perguntas aqui" }
}'
Com o SDK Python fica mais confortável, porque você monta as perguntas como objetos:
# o SDK lê TYPESAFE_API_KEY do ambiente e usa jev-latest por padrão
result = client.system_one(
state=state,
questions={
"proxima_pergunta": Choice(
instructions="Escolha qual pergunta do onboarding pedir agora",
criteria=CRITERIA_PERGUNTAS, # inclui none_of_the_above
),
"pode_encerrar": Noul(
instructions="Já temos informação suficiente para liberar o app?",
criteria=CRITERIA_ENCERRAMENTO,
),
},
)
proxima = result.answers["proxima_pergunta"] # opção + probabilidades + confidence
encerrar = result.answers["pode_encerrar"] # número: 0 = não, 1 = sim
As chaves do mapa questions são definidas por quem chama, e as respostas voltam sob as mesmas chaves
Isso é muito massa na prática: você nomeia as decisões do seu produto (proxima_pergunta, pode_encerrar) e lê o resultado por esse nome, sem tradução no meio
O erro comum deste passo: usar só a opção vencedora e ignorar confidence. A confiança vem da distribuição de probabilidade, e distribuição mais achatada significa confiança menor, então ela é o seu sinal de "não confia cegamente nessa escolha"
5. Decidir quando encerrar com um Noul na MESMA requisição:
Repara que eu mandei proxima_pergunta e pode_encerrar juntas ali em cima
Dá certo porque as duas são independentes: cada uma olha o mesmo state e responde por conta própria
E aqui entra a regra de arquitetura que você precisa entender pra não se enganar: perguntas enviadas na mesma requisição são avaliadas em paralelo contra o state e não enxergam a resposta umas das outras
Quando uma decisão depende da outra, elas viram etapas separadas. O critério prático, segundo o cookbook de perguntas paralelas, é esse: uma segunda requisição se justifica quando seu código não consegue montar o segundo request sem a primeira resposta
Vale agrupar tudo que for independente, e o ganho não é pequeno: no exemplo oficial, 13 perguntas em uma única chamada saíram 12,2x mais baratas e 10,0x mais rápidas, sem mudança nas respostas
No onboarding, isso significa mandar junto o Choice da próxima pergunta, o Noul de encerramento e, se você quiser, um Score de perfil na mesma leva
LIMIAR_ENCERRAR = 0.8
if encerrar >= LIMIAR_ENCERRAR:
finalizar_onboarding()
O erro comum deste passo: esperar que o pode_encerrar "saiba" qual pergunta o Choice escolheu. Ele não sabe, e nem precisa: os dois olham o mesmo state, e a decisão final de parar é do seu código
6. Fechar o loop: renderizar, gravar, repetir:
O ciclo é bobo depois que as peças estão no lugar:
while True:
result = decidir_proximo_campo(state)
if result.encerrar >= LIMIAR_ENCERRAR:
break
pergunta_id = result.pergunta_id
if pergunta_id in ("none_of_the_above",) or pergunta_id not in BANCO_DE_PERGUNTAS:
pergunta_id = proxima_da_ordem_fixa(state)
if pergunta_id is None:
break
resposta = renderizar_e_aguardar(pergunta_id) # front-end, usuário responde
state["respostas_coletadas"].update({pergunta_id: resposta})
state["perguntas_ja_feitas"].append(pergunta_id)
Cada rodada é uma requisição nova, e isso é correto e inevitável: seu código só consegue montar o request seguinte depois que o usuário respondeu o campo anterior

Crie sistemas com IA para vender
Prompts, modelos e checklists para criar e publicar seu sistema com IA e preparar a oferta para o primeiro cliente.
Quero o e-book gratuito Receba o livro e os bônus no seu e-mail.O erro comum deste passo: tentar "pré-decidir" as 5 próximas perguntas de uma vez pra economizar chamada. Não funciona, porque as perguntas da mesma requisição não veem a resposta uma da outra, e o valor todo do adaptativo está em reagir ao que o usuário acabou de digitar
Problemas comuns no formulário adaptativo (e como prevenir)
O Jev "inventa" uma pergunta que não existe no seu banco:
Sintoma: volta um ID que seu front não sabe renderizar, e a tela fica em branco
Causa: opções mal delimitadas, ou nenhuma opção de escape, então o modelo foi obrigado a escolher algo que não encaixava
Solução: Choice fechado usando os IDs reais do seu banco de perguntas, other ou none of the above presente, e validação do ID retornado antes de renderizar qualquer coisa. Aquele if pergunta_id not in BANCO_DE_PERGUNTAS do passo 6 não é paranoia, é guardrail (limite) básico
Confidence baixo e distribuição achatada:
Sintoma: a opção vencedora ganha por pouco, e as escolhas do fluxo parecem aleatórias entre usuários parecidos
Causa: nenhuma opção é vencedora clara, o que normalmente significa que duas perguntas restantes são igualmente úteis (ou igualmente inúteis) naquele ponto
Solução: fallback pra ordem fixa do formulário quando a confiança fica abaixo do seu limiar. E calibra esse limiar pela consequência do erro: pedir "tamanho do time" fora de hora é chato, mas disparar um bloqueio de conta errado é outro nível, então o número não pode ser o mesmo nos dois casos. Vale a mesma lógica de limiar que aparece quando você usa o modelo pra qualificar e priorizar leads
Texto colado pelo usuário influenciando a decisão:
Sintoma: um usuário escreve algo no campo livre e, do nada, o fluxo pula blocos inteiros do onboarding
Causa: conteúdo não confiável dentro do state pode influenciar o veredito do Jev. Em teste publicado, um contexto falso alegando pré-aprovação derrubou a probabilidade de bloqueio de 0,76 para 0,48, e marcar o documento como não confiável não mudou o resultado
A Check Point publicou análise de injeção de prompt contra o Jev mostrando que o problema existe mesmo num modelo de decisão tipada
Prevenção: separar campos de texto livre do contexto de decisão (manda categoria normalizada, não o texto cru), e nunca deixar a saída disparar ação sensível sozinha. Escolher o próximo campo é baixo risco, liberar limite de crédito não é. Se o seu produto recebe texto de usuário de verdade, o mesmo cuidado que vale pra moderar conteúdo enviado por usuários vale aqui
E quando o histórico do onboarding cresce?
Tem teto de contexto, e é bom saber antes de bater nele: o orçamento é de 64k tokens por requisição, dos quais 32k valem para o state mais a pergunta mais longa
Onboarding normal não chega perto disso, mas fluxo longo com texto colado chega
O que fazer: guarda no state o resumo estruturado das respostas (chave e valor), não a transcrição. E corta do state o que não muda decisão nenhuma, tipo timestamps de cada clique
Onde esse padrão rende mais que um formulário fixo
- Onboarding de SaaS que ramifica por perfil: dev solo não precisa responder sobre políticas de time, e time de 40 pessoas não precisa responder "você já programou antes?". O Choice resolve essa bifurcação sem você manter uma árvore de
ifgigante - KYC e cadastro com dados vindos de integração: quando parte dos campos já chegou de uma fonte externa, o state carrega isso em
campos_vindos_de_integracaoe o modelo simplesmente não escolhe aquelas perguntas. Bloco inteiro pulado - Quiz de recomendação de plano: aqui o Score brilha, porque em vez de perguntar "qual seu nível?" você posiciona o usuário num espectro a partir do que ele já disse
- Pesquisa pós-cadastro que encerra cedo: o Noul de encerramento vira o seu botão de "chega, já entendemos o suficiente", e a pesquisa acaba em 3 perguntas em vez de 10
E quando NÃO usar? Se o seu formulário tem 4 campos, deixa fixo
Se a ordem das perguntas é obrigatória por regulação ou por contrato, deixa fixo também: nesse caso o adaptativo só adiciona uma variável a mais pra auditar, e a complexidade não se paga
Próximo passo
O padrão inteiro cabe em quatro peças: state com o que você já sabe, Choice fechado nos IDs reais com opção de escape, Noul de encerramento na mesma requisição, e um loop que grava a resposta e chama de novo
O resto é o seu formulário de sempre
Pra sair do papel: cria a conta no console, usa os US$ 5 de crédito gratuito e roda o loop com 3 ou 4 perguntas reais do seu onboarding
Depois mede a coisa que importa, que é quantos campos o fluxo economizou por usuário, antes de colocar em produção
Pra fechar o orçamento de resposta do formulário, as referências públicas: a versão publicada hoje é a jev-1.13, os limites de taxa divulgados são 250.000 tokens por segundo e 1.200 requisições por minuto, e a faixa de latência divulgada pela própria TypeSafe pra uma decisão é de 70ms a 500ms (número do fornecedor, não de leaderboard público)
Ou seja: cabe dentro do tempo entre o usuário clicar em "continuar" e o próximo campo aparecer, que é exatamente onde esse tipo de decisão precisa viver
Se você montar esse loop no seu produto, me conta como ficou a taxa de conclusão… 🙂
até o próximo post!
Perguntas frequentes
Quantas perguntas dá pra colocar dentro de uma única opção Choice no onboarding?
Uma pergunta Choice suporta até 255 opções, então o catálogo de perguntas do seu onboarding cabe tranquilo numa chamada só. Isso é bem mais do que qualquer formulário sadio costuma ter. Se você chegar perto desse limite, provavelmente vale repensar o design do formulário.
Compensa mandar todas as perguntas do formulário numa chamada só ou é melhor separar em várias requisições?
Perguntas independentes que não dependem da resposta umas das outras podem ir juntas na mesma requisição, porque são avaliadas em paralelo contra o state. Agrupar o que é independente numa chamada só reduz custo e latência, sem mudar as respostas. Uma segunda requisição só se justifica quando seu código não consegue montar o segundo request sem a resposta da primeira pergunta.
Quanto custa manter um formulário adaptativo com Jev rodando em produção?
O preço publicado é de US$ 0,042 por 1 milhão de tokens de entrada, e os tokens de saída custam US$ 0. Como a resposta do Jev é tipada e curta, quem realmente pesa na conta é o tamanho do seu state a cada chamada. Vale normalizar o que entra ali em vez de mandar o dump inteiro do formulário.
É arriscado colocar texto que o próprio usuário digitou dentro do state que vai pro Jev?
Sim, conteúdo não confiável dentro do state pode influenciar o veredito do modelo. Em teste publicado, um contexto falso alegando pré-aprovação derrubou a probabilidade de bloqueio, e só marcar o documento como não confiável não mudou esse resultado. Já existe pesquisa de segurança independente sobre injeção de prompt contra esse tipo de modelo de decisão tipada, vale a leitura antes de expor o state a input direto do usuário.
Preciso entrar numa fila de espera pra usar o Jev no meu onboarding?
Não, o waitlist caiu quando a TypeSafe anunciou disponibilidade geral em 21 de setembro de 2026. O cadastro em console.typesafe.ai está aberto a qualquer pessoa e vem com US$ 5 de crédito gratuito pra você testar o formulário adaptativo com Jev antes de decidir colocar em produção.
Qual a diferença entre usar Choice e Noul pra decidir a próxima pergunta do onboarding?
Choice escolhe QUAL pergunta pedir agora entre as opções que ainda restam, devolvendo a opção escolhida junto com a probabilidade de cada uma e um confidence entre 0 e 1. Noul resolve outro problema: devolve um único número entre 0 e 1 dizendo se já dá pra encerrar o onboarding. No fluxo adaptativo os dois rodam juntos, Choice decide o próximo campo e Noul decide quando parar de perguntar.
Formações
Formação Claude Code
Domine Claude Code do absoluto zero até o avançado
- 120 aulas
- 4 projetos
- 9h 48min
Blog | Mais populares

Como montar um workflow de automação combinando decisões do Jev em código
Aprenda a montar um workflow com Jev: decisões tipadas encadeadas em código, alta confiança agindo sozinha e casos incertos escalando para revisão.

Jev decide, LLM escreve: como dividir os papéis dentro de um agente de IA
Jev é o modelo que decide, não escreve: entenda como dividir papéis entre Jev e LLM dentro de um agente de IA e quando usar cada um.

Para quem o Jev serve (e para quem não serve)?
Jev serve pra roteamento, scoring e guardrails em IA, não pra texto ou código. Veja pra quem o Jev serve e quando evitar.
