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

diagrama de formulário adaptativo com Jev decidindo a próxima pergunta do onboarding
Resposta rápida

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_KEY configurada, porque o cliente oficial lê a chave dali e chama jev-latest por 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

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"]
      }
    }
  }
}

O 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

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 if gigante
  • 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_integracao e 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.




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